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

news/2025/10/8 21:56:14/文章来源:https://www.cnblogs.com/infinilabs/p/19130169

背景问题

前阵子,社区有小伙伴在使用 Easysearch 的数据压缩功能时发现,在开启 source_reuse 和 ZSTD 后,一个字段的内容看不到了。

索引的设置如下:

{......"settings": {"index": {"codec": "ZSTD","source_reuse": "true"}},"mappings": {"dynamic_templates": [{"message_field": {"path_match": "message","mapping": {"norms": false,"type": "text"},"match_mapping_type": "string"}},{"string_fields": {"mapping": {"norms": false,"type": "text","fields": {"keyword": {"ignore_above": 256,"type": "keyword"}}},"match_mapping_type": "string","match": "*"}}]......
}

然后产生的一个多字段内容能被搜索到,但是不可见

类似于下面的这个情况:

原因分析

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

  1. 字段写入索引的时候,不仅写了 text 字段也写了 keyword 字段。
  2. keyword 字段产生倒排索引的时候,会忽略掉长度超过 ignore_above 的内容。
  3. 因为开启了 source_reuse,_source 字段中与 doc_values 或倒排索引重复的部分会被去除
  4. 产生的数据文件进行了 ZSTD 压缩,进一步提高了数据的压缩效率。
  5. 索引进行倒排或者 docvalue 的查询,检索到这个文档进行展示。
  6. 展示的时候通过文档 id 获取 _source或者docvalues_fields的内容来展示文本,但是文本内容是空的。

其中步骤 4 中的 ZSTD 压缩,是作用于数据文件的,并不对数据内容进行修改。因此,我们来专注于其他环节。

问题复现

首先,这个字段索引的配置也是一个 es 常见的设置,并不会带来内容显示缺失的问题。

            "mapping": {"type": "text","fields": {"keyword": {"ignore_above": 256,"type": "keyword"}}},

那么,source_reuse 就成了我们可以重点排查的环节。

source 发生了什么

source_reuse 的作用描述如下:

source_reuse: 启用 source_reuse 配置项能够去除 _source 字段中与 doc_values 或倒排索引重复的部分,从而有效减小索引总体大小,这个功能对日志类索引效果尤其明显。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. 创建不带source的双字段索引PUT test_source
{"mappings": {"_source": {"enabled": false},"properties": {"msg": {"type": "text","fields": {"keyword": {"ignore_above": 256,"type": "keyword"}}}}}
}# 2. 写入测试数据POST test_source/_doc/1
{"msg":"""[08-27 14:28:45] [DBG] [config.go:273] config contain variables, try to parse with environments
[08-27 14:28:45] [DBG] [config.go:214] load config files: []
[08-27 14:28:45] [INF] [pipeline.go:419] creating pipeline: pipeline_logging_merge
[08-27 14:28:45] [INF] [pipeline.go:419] creating pipeline: ingest_pipeline_logging
[08-27 14:28:45] [INF] [pipeline.go:419] creating pipeline: async_messages_merge
[08-27 14:28:45] [INF] [pipeline.go:419] creating pipeline: metrics_merge
[08-27 14:28:45] [INF] [pipeline.go:419] creating pipeline: request_logging_merge
[08-27 14:28:45] [INF] [pipeline.go:419] creating pipeline: ingest_merged_requests
[08-27 14:28:45] [INF] [pipeline.go:419] creating pipeline: async_ingest_bulk_requests
[08-27 14:28:45] [INF] [module.go:159] started module: pipeline
[08-27 14:28:45] [DBG] [module.go:163] all system module are started
[08-27 14:28:45] [DBG] [floating_ip.go:348] setup floating_ip, root privilege are required
[08-27 14:28:45] [DBG] [queue_config.go:121] init new queue config:e60457c6eae50a4eabbb62fc1001dccc,bulk_requests
[08-27 14:28:45] [DBG] [queue_config.go:121] init new queue config:e60457c6eae50a4eabbb62fc1001dccc,bulk_requests
[08-27 14:28:45] [DBG] [queue_config.go:121] init new queue config:e60457c6eae50a4eabbb62fc1001dccc,bulk_requests
[08-27 14:28:45] [DBG] [processor.go:139] generated new processors: indexing_merge
[08-27 14:28:45] [DBG] [pipeline.go:466] processing pipeline_v2: metrics_merge
[08-27 14:28:45] [DBG] [processor.go:139] generated new processors: when
[08-27 14:28:45] [DBG] [pipeline.go:466] processing pipeline_v2: ingest_merged_requests
[08-27 14:28:45] [DBG] [processor.go:139] generated new processors: indexing_merge
[08-27 14:28:45] [DBG] [pipeline.go:466] processing pipeline_v2: request_logging_merge
[08-27 14:28:45] [DBG] [processor.go:139] generated new processors: indexing_merge
[08-27 14:28:45] [DBG] [pipeline.go:466] processing pipeline_v2: async_messages_merge
[08-27 14:28:45] [DBG] [processor.go:139] generated new processors: bulk_indexing
[08-27 14:28:45] [DBG] [pipeline.go:466] processing pipeline_v2: ingest_pipeline_logging
[08-27 14:28:45] [DBG] [queue_config.go:121] init new queue config:1216c96eb876eee5b177d45436d0a362,gateway-pipeline-logs
[08-27 14:28:45] [DBG] [processor.go:139] generated new processors: bulk_indexing
[08-27 14:28:45] [DBG] [processor.go:139] generated new processors: indexing_merge
[08-27 14:28:45] [DBG] [pipeline.go:466] processing pipeline_v2: pipeline_logging_merge
[08-27 14:28:45] [DBG] [pipeline.go:466] processing pipeline_v2: async_ingest_bulk_requests
[08-27 14:28:45] [DBG] [badger.go:110] init badger database [queue_consumer_commit_offset]
[08-27 14:28:45] [INF] [floating_ip.go:290] floating_ip entering standby mode
[08-27 14:28:45] [DBG] [badger.go:110] init badger database [dis_locker]
[08-27 14:28:45] [DBG] [time.go:208] refresh low precision time in background
[08-27 14:28:45] [DBG] [domain_actions.go:278] elasticsearch metadata [backup] was not found
[08-27 14:28:45] [DBG] [bulk_indexing.go:355] metadata for [backup] is nil
[08-27 14:28:50] [INF] [module.go:178] started plugin: floating_ip
[08-27 14:28:50] [INF] [module.go:178] started plugin: force_merge
[08-27 14:28:50] [DBG] [network.go:78] network io stats will be included for map[]
[08-27 14:28:50] [INF] [module.go:178] started plugin: metrics
[08-27 14:28:50] [INF] [module.go:178] started plugin: statsd
[08-27 14:28:50] [DBG] [entry.go:100] reuse port 0.0.0.0:7005
[08-27 14:28:50] [DBG] [metrics.go:205] collecting network metrics
[08-27 14:28:50] [DBG] [metrics.go:174] collecting instance metrics
[08-27 14:28:50] [DBG] [elasticsearch.go:128] init elasticsearch proxy instance: prod
[08-27 14:28:50] [DBG] [filter.go:103] generated new filters: when, elasticsearch
[08-27 14:28:50] [DBG] [entry.go:142] apply filter flow: [*] [/_bulk] [ filters ]
[08-27 14:28:50] [DBG] [entry.go:142] apply filter flow: [*] [/{any_index}/_bulk] [ filters ]
[08-27 14:28:50] [DBG] [elasticsearch.go:128] init elasticsearch proxy instance: prod
[08-27 14:28:50] [DBG] [filter.go:103] generated new filters: request_path_limiter, elasticsearch
[08-27 14:28:50] [INF] [module.go:178] started plugin: gateway
[08-27 14:28:50] [DBG] [module.go:182] all user plugin are started
[08-27 14:28:50] [INF] [module.go:184] all modules are started
[08-27 14:28:50] [INF] [app.go:556] gateway is up and running now.
[08-27 14:28:50] [DBG] [domain_actions.go:278] elasticsearch metadata [backup] was not found
[08-27 14:28:50] [DBG] [bulk_indexing.go:355] metadata for [backup] is nil
[08-27 14:28:55] [DBG] [domain_actions.go:278] elasticsearch metadata [backup] was not found
[08-27 14:28:55] [DBG] [bulk_indexing.go:355] metadata for [backup] is nil
[08-27 14:29:00] [DBG] [metrics.go:205] collecting network metrics
[08-27 14:29:00] [DBG] [metrics.go:174] collecting instance metrics
[08-27 14:29:00] [DBG] [domain_actions.go:278] elasticsearch metadata [backup] was not found
[08-27 14:29:00] [DBG] [bulk_indexing.go:355] metadata for [backup] is nil
[08-27 14:29:05] [DBG] [domain_actions.go:278] elasticsearch metadata [backup] was not found
[08-27 14:29:05] [DBG] [bulk_indexing.go:355] metadata for [backup] is nil
[08-27 14:29:10] [DBG] [metrics.go:205] collecting network metrics
[08-27 14:29:10] [DBG] [metrics.go:174] collecting instance metrics
[08-27 14:29:10] [DBG] [domain_actions.go:278] elasticsearch metadata [backup] was not found"""}# 3. 查询数据
GET test_source/_search

此时,可以看到,存入的文档检索出来是空的

_source 字段是用于索引时传递的原始 JSON 文档主体。它本身未被索引成倒排(因此不作用于 query 阶段),只是在执行查询时用于 fetch 文档内容。

对于 text 类型,关闭_source,则字段内容自然不可被查看。

而对于 keyword 字段,查看_source也是不行的。可是 keyword 不仅存储source,还存储了 doc_values。因此,对于 keyword 字段类型,可以考虑关闭_source,使用 docvalue_fields 来查看字段内容。

测试如下:

# 1. 创建测试条件的索引
PUT test_source2
{"mappings": {"_source": {"enabled": false},"properties": {"msg": {"type": "keyword"}}}
}# 2. 写入数据
POST test_source2/_doc
{"msg":"1111111"}# 3. 使用 docvalue_fields 查询数据
POST test_source2/_search
{"docvalue_fields": ["msg"]}# 返回结果
{"took": 1,"timed_out": false,"_shards": {"total": 1,"successful": 1,"skipped": 0,"failed": 0},"hits": {"total": {"value": 1,"relation": "eq"},"max_score": 1,"hits": [{"_index": "test_source2","_type": "_doc","_id": "yBvTj5kBvrlGDwP29avf","_score": 1,"fields": {"msg": ["1111111"]}}]}
}

如果是 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. 创建测试条件的索引,ignore_above 设置为3
PUT test_source3
{"mappings": {"_source": {"enabled": false},"properties": {"msg": {"type": "keyword","ignore_above": 3}}}
}# 2. 写入数据,
POST test_source3/_doc
{"msg":"1111111"}POST test_source3/_doc
{"msg":"11"}# 3. 使用 docvalue_fields 查询数据
POST test_source3/_search
{"docvalue_fields": ["msg"]}# 返回内容
{"took": 363,"timed_out": false,"_shards": {"total": 1,"successful": 1,"skipped": 0,"failed": 0},"hits": {"total": {"value": 2,"relation": "eq"},"max_score": 1,"hits": [{"_index": "test_source3","_type": "_doc","_id": "yhvjj5kBvrlGDwP22KsG","_score": 1},{"_index": "test_source3","_type": "_doc","_id": "yxvzj5kBvrlGDwP2Nav6","_score": 1,"fields": {"msg": ["11"]}}]}
}

OK! 问题终于复现了。我们再来看看作为关键因素的 ignore_above 参数是用来干嘛的。

ignore_above:任何长度超过此整数值的字符串都不应被索引。默认值为 2147483647。默认动态映射会创建一个 ignore_above 设置为 256 的 keyword 子字段。

也就是说,ignore_above 在(倒排)索引时会截取内容,防止产生的索引内容过长。

但是从测试的两个文本来看,面对在参数范围内的文档,docvalues 会正常创建,而超出参数范围的文本而忽略创建(至于这个问题背后的源码细节我们可以另外开坑再鸽,此处省略)。

那么,在 source_reuse 下,keyword 的 ignore_above 是不是起到了相同的作用呢?

我们可以在问题场景上去除 ignore_above,参数试试,来看下面的测试:

# 1. 创建测试条件的索引,使用 source_reuse,设置 ignore_above 为3
PUT test_source4
{"settings": {"index": {"source_reuse": "true"}},"mappings": {"properties": {"msg": {"type": "text","fields": {"keyword": {"ignore_above": 3,"type": "keyword"}}}}}
}# 2. 写入数据
POST test_source4/_doc
{"msg":"1111111"}POST test_source4/_doc
{"msg":"11"}# 3. 使用 docvalue_fields 查询数据
POST test_source4/_search# 返回内容
{"took": 1,"timed_out": false,"_shards": {"total": 1,"successful": 1,"skipped": 0,"failed": 0},"hits": {"total": {"value": 2,"relation": "eq"},"max_score": 1,"hits": [{"_index": "test_source4","_type": "_doc","_id": "zBv2j5kBvrlGDwP2_au-","_score": 1,"_source": {}},{"_index": "test_source4","_type": "_doc","_id": "zRv2j5kBvrlGDwP2_qsO","_score": 1,"_source": {"msg": "11"}}]}
}

可以看到,数据“不可见”的问题被完整的复现了。

小结

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

  1. 在 source_reuse 的压缩使用中,keyword 字段的 ignore_ablve 参数尽量使用默认值,不要进行过短的设置(这个 tip 已补充在 Easysearch 文档中)。
  2. 在 source_reuse 是对数据压缩常见方法-关闭 source 字段的产品化处理,在日志压缩场景中有效且便捷,可以考虑多加利用。
  3. keyword 的 ignore_above 参数,不仅超出长度范围不进行倒排索引,也不会写入 docvalues。

特别感谢:社区@牛牪犇群

更多 Easysearch 资料请查看 官网文档。

作者:金多安,极限科技(INFINI Labs)搜索运维专家,Elastic 认证专家,搜索客社区日报责任编辑。一直从事与搜索运维相关的工作,日常会去挖掘 ES / Lucene 方向的搜索技术原理,保持搜索相关技术发展的关注。
原文:https://infinilabs.cn/blog/2025/invisibility-in-easysearch-field/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/931983.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QOJ856 Cactus 广义串并联图

题意 给定一棵仙人掌, 你需要用 \(k\) 种颜色给每个结点染色, 且保证有边相连的结点的颜色不相同, 求染色的方案数对 \(10^9+7\) 取模的结果。仙人掌定义为一张特殊的无向图, 其中每条边至多在一个简单环上。 题解 因为…

CF2152 订题

context A 除了最小的数字每种数字都会占用一次,去重后直接输出 \(2n-1\) 即可。 B 太神秘了,先咕咕咕。 C 发现如果一个区间内存在至少一个长度 \(\ge 2\) 的同色连续段,那么这个连续段可以通过删除两个同色之间的…

TortoiseSVN账号切换 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

房产中介 网站开发天津招投标天津建设工程信息网

电脑 远程桌面连接你的凭据不工作解决方法 方法/步骤 第一步我们首先需要知道远程桌面连接你的凭据不工作原因是,远程的电脑拒绝了访问,需要设置在远程的电脑上设置安全选项,按winR键,打开运行,输入“gpedit.msc”&a…

GJ Round 2025赛季

Round 1 (9.1) A给定正整数序列 \(a_1,a_2,\cdots,a_n\),对于 \(\forall k \in [0,n] \cap \mathbb Z\),完成以下问题: 令 \(S \subseteq A = \{1,2,\cdots,n\}\),当且仅当存在一个集合 \(T \subseteq S\),满足 \…

resolvers: [ElementPlusResolver()] 有什么用? - 详解

resolvers: [ElementPlusResolver()] 有什么用? - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&…

ASP.NET Core 中读取 UserAgent 的正确姿势

今天读了 Andrew Lock 的2篇博文学到的招式,记录一下。 两篇博文的链接:Using default interface methods for performance gains in IHeaderDictionary A brief look at StringValues之前的读取 UserAgent 的代码:…

Git学习记录(二):代码patch

Git中的一笔commit提交,可以成为patch生成Patch带有commit信息: git format-patch -1 HEAD only代码应用Patchcheck是否有冲突 git apply --check 0001-xxx.patch 应用Patchgit apply 0001-xxxx.patch git am 0001-xx…

网站开发有关费用网站建设服务费一年多少钱

Ubuntu从起后居然把Windows的设置给记住了。显示ok。我晕。以前倒是也有过这问题,在双系统情况下,外接键盘的灯会继承Windows的早就有心弄个显示器,把笔记本的外接上,倒不是说非要2个屏幕来工作如何如何?只是因为我的本…

2025年10月化妆品代工厂最新推荐排行榜:聚焦 OEM/ODM/ 网红爆款需求,精选优质企业助品牌高效合作

2025 年化妆品 ODM 行业规模预计突破 1128 亿元,功效型护肤等细分领域增速迅猛,但行业内企业资质悬殊问题突出。部分代工企业缺乏核心研发能力,配方同质化严重难以适配 “成分党” 需求;部分生产标准落后,未达十万…

西安地产网站制作公司四川网站建设公司 登录

## 路由与伪静态### 路由>[info] 字面上解释,路是线路,道路;由,缘由,指意,表示规则;所以意思就是按照什么规则,或者意义,被指派到什么地方去。所以路由是指线路分发&a…

Exchange安全漏洞分析:ProxyOracle攻击链详解

本文深入分析Microsoft Exchange中的ProxyOracle攻击链,包含CVE-2021-31195 XSS漏洞和CVE-2021-31196填充Oracle攻击,攻击者可通过恶意链接获取用户明文密码,涉及FBA认证机制和加密cookie解析过程。Orange:MS Exch…

北京建站公司哪家好都选万维科技电脑维护网站模板

题目链接 2865. 美丽塔 I - 力扣(LeetCode) 解题思路 根据题意可以知道,假设数组的长度为n,对于山状数组heights定义如下: 假设heights[i]为数组中的最大值,则i左边的值均小于等于heights[i],i右边的值…

将word档案转为kindle可识别的azw3材料的方法

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

牛客 周赛111 20251008

牛客 周赛111 20251009 https://ac.nowcoder.com/acm/contest/117763 A: 题目大意: void solve(){int a, b, c;cin >> a >> b >> c;if (b != a + 1 || c != b + 1) cout << "No";…

本人于2025上半学期编码需要遵守的规范(参考腾讯内部编码规范)

编码的规范可以使代码更加具有易维护性以及编码安全性等等 程序的板式 缩进使用 4 个空格,禁止混用 Tab 键。 行宽限制 80 字符,长表达式在低优先级操作符处换行,操作符置于新行首。 大括号{}独占一行并与代码对齐,…

常州语言网站建设龙岩网站开发

hw_breakpoint 是由处理器提供专门断点寄存器来保存一个地址&#xff0c;是需要处理器支持的。处理器在执行过程中会不断去匹配&#xff0c;当匹配上后则会产生中断。 内核自带了硬件断点的样例linux-3.16\samples\hw_breakpoint\data_breakpoint.c static void sample_hbp_h…

tp做的网站封装成app定制网站建设公司有哪些

抖音短视频规则一、抖音的定义1、抖音是个去中心化的平台&#xff0c;根本没有什么权重&#xff0c;主要是看你账号的活跃度&#xff0c;互动关系&#xff0c;和行为习惯标签&#xff0c;抖音后台技术有去重机制&#xff0c;机器会自动判断你的视频重复率。重复率达到一定的比例…

图片素材网站免费大推荐网站正在备案

我想在recyclerview中显示一些JSON对象&#xff0c;并且希望它们在日期之后排序&#xff0c;我该如何实现&#xff1f;下面是下载从JSON URL的数据的方法&#xff1a;Android Studio Studio回收列表中的JSON对象public void downloadFromSkistar(){try{URL url new URL("…

泰安网站建设怎么样网上做兼职做网站

转载公众号 | 计算机科学编辑部征稿“知识图谱赋能的知识工程&#xff1a;理论、技术与系统”专题知识图谱&#xff08;Knowledge Graph&#xff09;方法与技术是人工智能在知识工程领域发展的最新前沿。知识图谱正在“感知智能”迈向“认知智能”的过程中扮演着重要角色。近年…