Easysearch 字段'隐身'之谜:source_reuse 与 ignore_above 的陷阱分析

[复制链接]
发表于 昨天 20:54 | 显示全部楼层 |阅读模式
配景题目

前阵子,社区有小搭档在使用 Easysearch 的数据压缩功能时发现,在开启 source_reuse 和 ZSTD 后,一个字段的内容看不到了。
索引的设置如下:
  1. {
  2.     ......
  3.     "settings": {
  4.       "index": {
  5.         "codec": "ZSTD",
  6.         "source_reuse": "true"
  7.       }
  8.     },
  9.     "mappings": {
  10.       "dynamic_templates": [
  11.         {
  12.           "message_field": {
  13.             "path_match": "message",
  14.             "mapping": {
  15.               "norms": false,
  16.               "type": "text"
  17.             },
  18.             "match_mapping_type": "string"
  19.           }
  20.         },
  21.         {
  22.           "string_fields": {
  23.             "mapping": {
  24.               "norms": false,
  25.               "type": "text",
  26.               "fields": {
  27.                 "keyword": {
  28.                   "ignore_above": 256,
  29.                   "type": "keyword"
  30.                 }
  31.               }
  32.             },
  33.             "match_mapping_type": "string",
  34.             "match": "*"
  35.           }
  36.         }
  37.       ]
  38.       ......
  39. }
复制代码
然后产生的一个多字段内容能被搜索到,但是不可见
类似于下面的这个环境:

缘故原由分析

我们先来看看整个字段展示履历的环节:


  • 字段写入索引的时间,不但写了 text 字段也写了 keyword 字段。
  • keyword 字段产生倒排索引的时间,会忽略掉长度凌驾 ignore_above 的内容。
  • 由于开启了 source_reuse,_source 字段中与 doc_values 或倒排索引重复的部分会被去除
  • 产生的数据文件举行了 ZSTD 压缩,进一步进步了数据的压缩服从。
  • 索引举行倒排大概 docvalue 的查询,检索到这个文档举行展示。
  • 展示的时间通过文档 id 获取 _source大概docvalues_fields的内容来展示文本,但是文本内容是空的。
此中步调 4 中的 ZSTD 压缩,是作用于数据文件的,并不对数据内容举行修改。因此,我们来专注于其他环节。
题目复现

起首,这个字段索引的设置也是一个 es 常见的设置,并不会带来内容表现缺失的题目。
  1.             "mapping": {
  2.               "type": "text",
  3.               "fields": {
  4.                 "keyword": {
  5.                   "ignore_above": 256,
  6.                   "type": "keyword"
  7.                 }
  8.               }
  9.             },
复制代码
那么,source_reuse 就成了我们可以重点排查的环节。
source 发生了什么

source_reuse 的作用形貌如下:
  1. source_reuse: 启用 source_reuse 配置项能够去除 _source 字段中与 doc_values 或倒排索引重复的部分,从而有效减小索引总体大小,这个功能日志日志类索引效果尤其明显。
  2. source_reuse 支持对以下数据类型进行压缩:keyword,integer,long,short,boolean,float,half_float,double,geo_point,ip, 如果是 text 类型,需要默认启用 keyword 类型的 multi-field 映射。 以上类型必须启用 doc_values 映射(默认启用)才能压缩。
复制代码
这是一个对 _source 字段举行产物化的功能实现。为了镌汰索引的存储体量,简朴粗暴的操纵是直接将_source字段举行关闭,使用其他数据格式去存储,在查询的时间对应的使用 docvalue 大概 indexed 去展示文本内容。
那么 _source关闭后,会不会也有如许的题目呢?
测试的步调如下:
  1. # 1. 创建不带source的双字段索引
  2. PUT test_source
  3. {
  4.   "mappings": {
  5.     "_source": {
  6.       "enabled": false
  7.     },
  8.     "properties": {
  9.       "msg": {
  10.         "type": "text",
  11.         "fields": {
  12.           "keyword": {
  13.             "ignore_above": 256,
  14.             "type": "keyword"
  15.           }
  16.         }
  17.       }
  18.     }
  19.   }
  20. }
  21. # 2. 写入测试数据
  22. POST test_source/_doc/1
  23. {"msg":"""[08-27 14:28:45] [DBG] [config.go:273] config contain variables, try to parse with environments
  24. [08-27 14:28:45] [DBG] [config.go:214] load config files: []
  25. [08-27 14:28:45] [INF] [pipeline.go:419] creating pipeline: pipeline_logging_merge
  26. [08-27 14:28:45] [INF] [pipeline.go:419] creating pipeline: ingest_pipeline_logging
  27. [08-27 14:28:45] [INF] [pipeline.go:419] creating pipeline: async_messages_merge
  28. [08-27 14:28:45] [INF] [pipeline.go:419] creating pipeline: metrics_merge
  29. [08-27 14:28:45] [INF] [pipeline.go:419] creating pipeline: request_logging_merge
  30. [08-27 14:28:45] [INF] [pipeline.go:419] creating pipeline: ingest_merged_requests
  31. [08-27 14:28:45] [INF] [pipeline.go:419] creating pipeline: async_ingest_bulk_requests
  32. [08-27 14:28:45] [INF] [module.go:159] started module: pipeline
  33. [08-27 14:28:45] [DBG] [module.go:163] all system module are started
  34. [08-27 14:28:45] [DBG] [floating_ip.go:348] setup floating_ip, root privilege are required
  35. [08-27 14:28:45] [DBG] [queue_config.go:121] init new queue config:e60457c6eae50a4eabbb62fc1001dccc,bulk_requests
  36. [08-27 14:28:45] [DBG] [queue_config.go:121] init new queue config:e60457c6eae50a4eabbb62fc1001dccc,bulk_requests
  37. [08-27 14:28:45] [DBG] [queue_config.go:121] init new queue config:e60457c6eae50a4eabbb62fc1001dccc,bulk_requests
  38. [08-27 14:28:45] [DBG] [processor.go:139] generated new processors: indexing_merge
  39. [08-27 14:28:45] [DBG] [pipeline.go:466] processing pipeline_v2: metrics_merge
  40. [08-27 14:28:45] [DBG] [processor.go:139] generated new processors: when
  41. [08-27 14:28:45] [DBG] [pipeline.go:466] processing pipeline_v2: ingest_merged_requests
  42. [08-27 14:28:45] [DBG] [processor.go:139] generated new processors: indexing_merge
  43. [08-27 14:28:45] [DBG] [pipeline.go:466] processing pipeline_v2: request_logging_merge
  44. [08-27 14:28:45] [DBG] [processor.go:139] generated new processors: indexing_merge
  45. [08-27 14:28:45] [DBG] [pipeline.go:466] processing pipeline_v2: async_messages_merge
  46. [08-27 14:28:45] [DBG] [processor.go:139] generated new processors: bulk_indexing
  47. [08-27 14:28:45] [DBG] [pipeline.go:466] processing pipeline_v2: ingest_pipeline_logging
  48. [08-27 14:28:45] [DBG] [queue_config.go:121] init new queue config:1216c96eb876eee5b177d45436d0a362,gateway-pipeline-logs
  49. [08-27 14:28:45] [DBG] [processor.go:139] generated new processors: bulk_indexing
  50. [08-27 14:28:45] [DBG] [processor.go:139] generated new processors: indexing_merge
  51. [08-27 14:28:45] [DBG] [pipeline.go:466] processing pipeline_v2: pipeline_logging_merge
  52. [08-27 14:28:45] [DBG] [pipeline.go:466] processing pipeline_v2: async_ingest_bulk_requests
  53. [08-27 14:28:45] [DBG] [badger.go:110] init badger database [queue_consumer_commit_offset]
  54. [08-27 14:28:45] [INF] [floating_ip.go:290] floating_ip entering standby mode
  55. [08-27 14:28:45] [DBG] [badger.go:110] init badger database [dis_locker]
  56. [08-27 14:28:45] [DBG] [time.go:208] refresh low precision time in background
  57. [08-27 14:28:45] [DBG] [domain_actions.go:278] elasticsearch metadata [backup] was not found
  58. [08-27 14:28:45] [DBG] [bulk_indexing.go:355] metadata for [backup] is nil
  59. [08-27 14:28:50] [INF] [module.go:178] started plugin: floating_ip
  60. [08-27 14:28:50] [INF] [module.go:178] started plugin: force_merge
  61. [08-27 14:28:50] [DBG] [network.go:78] network io stats will be included for map[]
  62. [08-27 14:28:50] [INF] [module.go:178] started plugin: metrics
  63. [08-27 14:28:50] [INF] [module.go:178] started plugin: statsd
  64. [08-27 14:28:50] [DBG] [entry.go:100] reuse port 0.0.0.0:7005
  65. [08-27 14:28:50] [DBG] [metrics.go:205] collecting network metrics
  66. [08-27 14:28:50] [DBG] [metrics.go:174] collecting instance metrics
  67. [08-27 14:28:50] [DBG] [elasticsearch.go:128] init elasticsearch proxy instance: prod
  68. [08-27 14:28:50] [DBG] [filter.go:103] generated new filters: when, elasticsearch
  69. [08-27 14:28:50] [DBG] [entry.go:142] apply filter flow: [*] [/_bulk] [ filters ]
  70. [08-27 14:28:50] [DBG] [entry.go:142] apply filter flow: [*] [/{any_index}/_bulk] [ filters ]
  71. [08-27 14:28:50] [DBG] [elasticsearch.go:128] init elasticsearch proxy instance: prod
  72. [08-27 14:28:50] [DBG] [filter.go:103] generated new filters: request_path_limiter, elasticsearch
  73. [08-27 14:28:50] [INF] [module.go:178] started plugin: gateway
  74. [08-27 14:28:50] [DBG] [module.go:182] all user plugin are started
  75. [08-27 14:28:50] [INF] [module.go:184] all modules are started
  76. [08-27 14:28:50] [INF] [app.go:556] gateway is up and running now.
  77. [08-27 14:28:50] [DBG] [domain_actions.go:278] elasticsearch metadata [backup] was not found
  78. [08-27 14:28:50] [DBG] [bulk_indexing.go:355] metadata for [backup] is nil
  79. [08-27 14:28:55] [DBG] [domain_actions.go:278] elasticsearch metadata [backup] was not found
  80. [08-27 14:28:55] [DBG] [bulk_indexing.go:355] metadata for [backup] is nil
  81. [08-27 14:29:00] [DBG] [metrics.go:205] collecting network metrics
  82. [08-27 14:29:00] [DBG] [metrics.go:174] collecting instance metrics
  83. [08-27 14:29:00] [DBG] [domain_actions.go:278] elasticsearch metadata [backup] was not found
  84. [08-27 14:29:00] [DBG] [bulk_indexing.go:355] metadata for [backup] is nil
  85. [08-27 14:29:05] [DBG] [domain_actions.go:278] elasticsearch metadata [backup] was not found
  86. [08-27 14:29:05] [DBG] [bulk_indexing.go:355] metadata for [backup] is nil
  87. [08-27 14:29:10] [DBG] [metrics.go:205] collecting network metrics
  88. [08-27 14:29:10] [DBG] [metrics.go:174] collecting instance metrics
  89. [08-27 14:29:10] [DBG] [domain_actions.go:278] elasticsearch metadata [backup] was not found"""}
  90. # 3. 查询数据
  91. GET test_source/_search
复制代码
此时,可以看到,存入的文档检索出来是空的

_source 字段是用于索引时转达的原始 JSON 文档主体。它自己未被索引成倒排(因此不作用于 query 阶段),只是在实行查询时用于 fetch 文档内容。
对于 text 范例,关闭_source,则字段内容自然不可被检察。
而对于 keyword 字段,检察_source也是不可的。但是 keyword 不但存储source,还存储了 doc_values。因此,对于 keyword 字段范例,可以思量关闭_source,使用 docvalue_fields 来检察字段内容。
测试如下:
  1. # 1. 创建测试条件的索引
  2. PUT test_source2
  3. {
  4.   "mappings": {
  5.     "_source": {
  6.       "enabled": false
  7.     },
  8.     "properties": {
  9.       "msg": {
  10.         "type": "keyword"
  11.       }
  12.     }
  13.   }
  14. }
  15. # 2. 写入数据
  16. POST test_source2/_doc
  17. {"msg":"1111111"}
  18. # 3. 使用 docvalue_fields 查询数据
  19. POST test_source2/_search
  20. {"docvalue_fields": ["msg"]}
  21. # 返回结果
  22. {
  23.   "took": 1,
  24.   "timed_out": false,
  25.   "_shards": {
  26.     "total": 1,
  27.     "successful": 1,
  28.     "skipped": 0,
  29.     "failed": 0
  30.   },
  31.   "hits": {
  32.     "total": {
  33.       "value": 1,
  34.       "relation": "eq"
  35.     },
  36.     "max_score": 1,
  37.     "hits": [
  38.       {
  39.         "_index": "test_source2",
  40.         "_type": "_doc",
  41.         "_id": "yBvTj5kBvrlGDwP29avf",
  42.         "_score": 1,
  43.         "fields": {
  44.           "msg": [
  45.             "1111111"
  46.           ]
  47.         }
  48.       }
  49.     ]
  50.   }
  51. }
复制代码
在假如是 text 范例,必要默认启用 keyword 范例的 multi-field 映射。 以上范例必须启用 doc_values 映射(默认启用)才气压缩。这句先容里,也可以看到 source_reuse 的正常使用必要 doc_values。那是不是一样使用 doc_values 举行内容展示呢?既然用于 docvalue_fields 内容展示,为什么照旧内容看不了(不可见)呢?
keyword 的 ignore_above

过细看题目场景里 keyword 的设置,它使用了 ignore_above。那么,会不会是这里的题目?
我们将 ignore_above 设置带入上面的测试,这里为了简化测试,ignore_above 设置为 3。为区分题目征象,这里两条长度差异的文本进去,一条为 11,一条为1111111,可以作为参数作用效果的对比
  1. # 1. 创建测试条件的索引,ignore_above 设置为3
  2. PUT test_source3
  3. {
  4.   "mappings": {
  5.     "_source": {
  6.       "enabled": false
  7.     },
  8.     "properties": {
  9.       "msg": {
  10.         "type": "keyword",
  11.         "ignore_above": 3
  12.       }
  13.     }
  14.   }
  15. }
  16. # 2. 写入数据,
  17. POST test_source3/_doc
  18. {"msg":"1111111"}
  19. POST test_source3/_doc
  20. {"msg":"11"}
  21. # 3. 使用 docvalue_fields 查询数据
  22. POST test_source3/_search
  23. {"docvalue_fields": ["msg"]}
  24. # 返回内容
  25. {
  26.   "took": 363,
  27.   "timed_out": false,
  28.   "_shards": {
  29.     "total": 1,
  30.     "successful": 1,
  31.     "skipped": 0,
  32.     "failed": 0
  33.   },
  34.   "hits": {
  35.     "total": {
  36.       "value": 2,
  37.       "relation": "eq"
  38.     },
  39.     "max_score": 1,
  40.     "hits": [
  41.       {
  42.         "_index": "test_source3",
  43.         "_type": "_doc",
  44.         "_id": "yhvjj5kBvrlGDwP22KsG",
  45.         "_score": 1
  46.       },
  47.       {
  48.         "_index": "test_source3",
  49.         "_type": "_doc",
  50.         "_id": "yxvzj5kBvrlGDwP2Nav6",
  51.         "_score": 1,
  52.         "fields": {
  53.           "msg": [
  54.             "11"
  55.           ]
  56.         }
  57.       }
  58.     ]
  59.   }
  60. }
复制代码
OK! 题目终于复现了。我们再来看看作为关键因素的 ignore_above 参数是用来干嘛的。
  1. ignore_above:任何长度超过此整数值的字符串都不应被索引。默认值为 2147483647。默认动态映射会创建一个 ignore_above 设置为 256 的 keyword 子字段。
复制代码
也就是说,ignore_above 在(倒排)索引时会截取内容,防止产生的索引内容过长。
但是从测试的两个文原来看,面临在参数范围内的文档,docvalues 会正常创建,而超出参数范围的文本而忽略创建(至于这个题目背后的源码细节我们可以别的开坑再鸽,此处省略)。
那么,在 source_reuse 下,keyword 的 ignore_above 是不是起到了类似的作用呢?
我们可以在题目场景上去除 ignore_above,参数试试,来看下面的测试:
  1. # 1. 创建测试条件的索引,使用 source_reuse,设置 ignore_above 为3
  2. PUT test_source4
  3. {
  4.   "settings": {
  5.     "index": {
  6.       "source_reuse": "true"
  7.     }
  8.   },
  9.   "mappings": {
  10.     "properties": {
  11.       "msg": {
  12.         "type": "text",
  13.         "fields": {
  14.           "keyword": {
  15.             "ignore_above": 3,
  16.             "type": "keyword"
  17.           }
  18.         }
  19.       }
  20.     }
  21.   }
  22. }
  23. # 2. 写入数据
  24. POST test_source4/_doc
  25. {"msg":"1111111"}
  26. POST test_source4/_doc
  27. {"msg":"11"}
  28. # 3. 使用 docvalue_fields 查询数据
  29. POST test_source4/_search
  30. # 返回内容
  31. {
  32.   "took": 1,
  33.   "timed_out": false,
  34.   "_shards": {
  35.     "total": 1,
  36.     "successful": 1,
  37.     "skipped": 0,
  38.     "failed": 0
  39.   },
  40.   "hits": {
  41.     "total": {
  42.       "value": 2,
  43.       "relation": "eq"
  44.     },
  45.     "max_score": 1,
  46.     "hits": [
  47.       {
  48.         "_index": "test_source4",
  49.         "_type": "_doc",
  50.         "_id": "zBv2j5kBvrlGDwP2_au-",
  51.         "_score": 1,
  52.         "_source": {}
  53.       },
  54.       {
  55.         "_index": "test_source4",
  56.         "_type": "_doc",
  57.         "_id": "zRv2j5kBvrlGDwP2_qsO",
  58.         "_score": 1,
  59.         "_source": {
  60.           "msg": "11"
  61.         }
  62.       }
  63.     ]
  64.   }
  65. }
复制代码
可以看到,数据“不可见”的题目被完备的复现了。
小结

从上面一系列针对数据“不可见”题目的测试,我们可以总结以下几点:

  • 在 source_reuse 的压缩使用中,keyword 字段的 ignore_ablve 参数只管使用默认值,不要举行过短的设置(这个 tip 已增补在 Easysearch 文档中)。
  • 在 source_reuse 是对数据压缩常见方法-关闭 source 字段的产物化处理惩罚,在日志日志压缩场景中有用且便捷,可以思量多加使用。
  • keyword 的 ignore_above 参数,不但超出长度范围不举行倒排索引,也不会写入 docvalues。
特别感谢:社区@牛牪犇群
更多 Easysearch 资料请检察 官网文档
作者:金多安,极限科技(INFINI Labs)搜索运维专家,Elastic 认证专家,搜索客社区日报责任编辑。不绝从事与搜索运维干系的工作,一样平常会去发掘 ES / Lucene 方向的搜索技能原理,保持搜索干系技能发展的关注。
原文:https://infinilabs.cn/blog/2025/invisibility-in-easysearch-field/

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表