主页 > 人工智能  > 

【实战ES】实战Elasticsearch:快速上手与深度实践-2.1.2字段类型选择:keywordvstex

【实战ES】实战Elasticsearch:快速上手与深度实践-2.1.2字段类型选择:keywordvstex

👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路


文章大纲 第2章 数据建模与高效写入:ES字段类型选择最佳实践:keyword vs text与nested对象深度解析1. 索引设计核心原则2. `keyword`与`text`类型终极对决2.1 核心差异对比2.2 性能基准测试数据2.3 经典使用场景 3. `nested`对象深度解析3.1 问题背景:`对象数组的扁平化---理解体会到扁平化这个词`3.2 `nested`类型解决方案3.3 nested与普通对象对比3.4 性能影响测试 4. 实战案例:电商平台商品模型设计4.1 需求分析4.2 最终映射设计4.3 查询示例:查找红色库存>100的商品 5. 最佳实践总结5.1 类型选择决策树5.2 黄金法则5.3 常见误区 附录:性能优化参数参考

第2章 数据建模与高效写入:ES字段类型选择最佳实践:keyword vs text与nested对象深度解析 1. 索引设计核心原则

在Elasticsearch中,字段类型的选择直接影响以下关键指标:

影响维度说明典型场景示例查询性能类型选择错误可能导致查询延迟增加5-10倍使用text类型进行精确匹配存储效率合理的类型可减少20-50%的磁盘占用数值类型误设为keyword聚合准确性错误类型会导致cardinality聚合误差率高达30%高基数字段使用text类型进行聚合功能支持特定功能(如地理位置查询)必须使用专用类型geo_point用于地理位置查询 cardinality 是 Elasticsearch 中的一种聚合类型,它可以对指定字段中的唯一值进行近似计数。 这里的 “近似” 是因为为了在处理大规模数据时提高性能和减少内存使用,cardinality 采用了 HyperLogLog++ 算法(算法的核心思想基于伯努利试验和概率统计)来估算唯一值的数量,而不是精确统计。 2. keyword与text类型终极对决 2.1 核心差异对比 特性keyword类型text类型分词处理不进行分词默认使用标准分词器存储结构原始值完整存储分词后存储倒排索引查询方式精确匹配(term查询)全文搜索(match查询)排序支持完全支持需要开启fielddata(消耗内存)聚合性能高效,适合terms聚合需要额外配置fielddata,性能较差典型应用场景标签、状态码、分类ID文章内容、产品描述、日志详情存储开销每个值独立存储分词后存储,可能有重复token模糊查询支持wildcard(性能差)支持多种分词器(如ngram) 2.2 性能基准测试数据 测试环境:3节点集群(16核32GB,NVMe SSD),数据集:1000万条商品记录 测试场景keyword类型耗时text类型耗时性能差异精确匹配查询(term)23ms520ms22.6倍全文搜索(match)N/A45ms-terms聚合(1000桶)680ms4200ms6.2倍存储空间占用12.4GB18.7GB1.5倍 2.3 经典使用场景 适用keyword的情况: { "product_id": {"type": "keyword"}, "category": { "type": "keyword", "ignore_above": 256 // 自动截断超长字段 }, "status": {"type": "keyword"} // 状态枚举值 } 适用text的情况: analyzer(分析器):将文本拆分成一个个独立的词项(term),并可对这些词项进行一系列处理,如转换大小写、去除停用词等。ik_max_word 分词器特点 ik_max_word 是 IK 分词器提供的一种分词模式。IK 分词器是一款专门为中文文本处理设计的开源分词器,在 Elasticsearch 中被广泛应用。ik_max_word 模式具有以下特点: 最大切分粒度:它会将文本进行最细粒度的拆分,尽可能地将文本拆分成更多的有意义的词。例如,对于 “研究生命起源” 这句话,ik_max_word 会将其拆分为 “研究”“研究生”“生命”“起源” 等词项,这样可以提高搜索的召回率,让更多可能相关的文档被检索出来。智能识别:能够智能识别中文词汇,包括一些常见的专业术语、人名、地名等,使得分词结果更符合中文语言习惯。 { "product_description": { "type": "text", "analyzer": "ik_max_word", // 使用中文分词器 "fields": { "keyword": {"type": "keyword"} // 多字段特性 } } } 3. nested对象深度解析 3.1 问题背景:对象数组的扁平化---理解体会到扁平化这个词 普通对象数组存储方式: { "order_id": "1001", "items": [ {"sku": "A001", "price": 99}, {"sku": "B002", "price": 199} ] } 实际存储结构: { "order_id": "1001", "items.sku": ["A001", "B002"], "items.price": [99, 199] } 3.2 nested类型解决方案 { "order": { "properties": { "items": { "type": "nested", "properties": { "sku": {"type": "keyword"}, "price": {"type": "double"} } } } } } 3.3 nested与普通对象对比 特性nested类型普通对象数组存储方式独立隐藏文档扁平化存储查询准确性精确维护对象关系可能产生跨对象匹配写入性能比普通对象慢2-3倍最优查询性能需要特殊查询语法,较慢标准查询语法适用场景需要精确维护对象关系的场景不需要维护关系的简单数组内存消耗每个nested对象单独索引整体作为字段处理 3.4 性能影响测试 测试数据集:500万订单记录,每个订单平均3个商品项 操作类型nested类型耗时普通对象耗时差异倍数写入吞吐量1,200 docs/s3,800 docs/s3.2倍嵌套查询220ms35ms6.3倍聚合分析1.8s0.9s2倍存储空间143GB89GB1.6倍 4. 实战案例:电商平台商品模型设计 4.1 需求分析 商品基础信息多规格SKU管理用户评论情感分析实时库存查询 4.2 最终映射设计 { "mappings": { "properties": { "product_id": {"type": "keyword"}, "title": { "type": "text", "analyzer": "ik_smart", "fields": {"keyword": {"type": "keyword"}} }, "categories": {"type": "keyword"}, "specs": { "type": "nested", "properties": { "color": {"type": "keyword"}, "size": {"type": "keyword"}, "stock": {"type": "integer"} } }, "reviews": { "type": "nested", "properties": { "user_id": {"type": "keyword"}, "content": {"type": "text"}, "rating": {"type": "byte"} } } } } } ik_smart 是 IK 分词器提供的一种分词模式。IK 分词器是专为中文文本处理打造的开源分词器,在 Elasticsearch 社区被广泛应用。ik_smart 模式具有以下显著特点: 最少切分原则:它会尽可能将文本进行最粗粒度的拆分,以最少的词数来表达文本的语义。例如,对于 “研究生命起源” 这句话,ik_smart 会将其拆分为 “研究”“生命起源”,这种切分方式更注重整体语义的表达。高效简洁:由于分词结果的词数相对较少,在处理大规模文本时,ik_smart 可以减少索引的大小,提高搜索效率,同时也能一定程度上降低计算资源的消耗。使用场景 对搜索效率要求高的场景:当需要快速处理大量中文文本搜索请求时,ik_smart 是一个不错的选择。例如,在电商网站的商品搜索功能中,用户输入搜索关键词后,系统需要迅速返回相关商品列表,使用 ik_smart 可以加快搜索速度,提升用户体验。注重整体语义匹配的场景:在一些对文本整体语义理解要求较高的搜索场景中,ik_smart 的粗粒度分词能够更好地捕捉文本的核心语义。比如,在企业知识管理系统中搜索相关文档时,用户更关注的是文档的整体主题,ik_smart 可以帮助找到更符合主题的文档。 4.3 查询示例:查找红色库存>100的商品 { "query": { "nested": { "path": "specs", "query": { "bool": { "must": [ {"term": {"specs.color": "red"}}, {"range": {"specs.stock": {"gt": 100}}} ] } } } } } 5. 最佳实践总结 5.1 类型选择决策树 #mermaid-svg-VddtHJksYwEnTGyo {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-VddtHJksYwEnTGyo .error-icon{fill:#552222;}#mermaid-svg-VddtHJksYwEnTGyo .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-VddtHJksYwEnTGyo .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-VddtHJksYwEnTGyo .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-VddtHJksYwEnTGyo .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-VddtHJksYwEnTGyo .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-VddtHJksYwEnTGyo .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-VddtHJksYwEnTGyo .marker{fill:#333333;stroke:#333333;}#mermaid-svg-VddtHJksYwEnTGyo .marker.cross{stroke:#333333;}#mermaid-svg-VddtHJksYwEnTGyo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-VddtHJksYwEnTGyo .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-VddtHJksYwEnTGyo .cluster-label text{fill:#333;}#mermaid-svg-VddtHJksYwEnTGyo .cluster-label span{color:#333;}#mermaid-svg-VddtHJksYwEnTGyo .label text,#mermaid-svg-VddtHJksYwEnTGyo span{fill:#333;color:#333;}#mermaid-svg-VddtHJksYwEnTGyo .node rect,#mermaid-svg-VddtHJksYwEnTGyo .node circle,#mermaid-svg-VddtHJksYwEnTGyo .node ellipse,#mermaid-svg-VddtHJksYwEnTGyo .node polygon,#mermaid-svg-VddtHJksYwEnTGyo .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VddtHJksYwEnTGyo .node .label{text-align:center;}#mermaid-svg-VddtHJksYwEnTGyo .node.clickable{cursor:pointer;}#mermaid-svg-VddtHJksYwEnTGyo .arrowheadPath{fill:#333333;}#mermaid-svg-VddtHJksYwEnTGyo .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-VddtHJksYwEnTGyo .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-VddtHJksYwEnTGyo .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-VddtHJksYwEnTGyo .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-VddtHJksYwEnTGyo .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-VddtHJksYwEnTGyo .cluster text{fill:#333;}#mermaid-svg-VddtHJksYwEnTGyo .cluster span{color:#333;}#mermaid-svg-VddtHJksYwEnTGyo div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-VddtHJksYwEnTGyo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是 否 是 否 是且需维护关系 否 需要全文搜索? 使用text类型 需要精确匹配? 使用keyword 包含子对象? 使用nested 使用合适的基础类型 5.2 黄金法则 标识性原则:唯一标识符必须使用keyword 长度控制:超过256字符的keyword字段需设置ignore_above 混合使用:重要文本字段应同时设置text和keyword 性能代价:nested类型要严格控制数组长度 版本兼容:7.x以上版本优先使用keyword替代string类型 5.3 常见误区 错误场景后果解决方案对text字段进行term查询返回结果不准确使用match查询或.keyword字段过度使用nested类型写入性能急剧下降评估是否真正需要对象关系维护大数组存储为keyword导致mapping爆炸使用flattened类型替代数值字段设为text范围查询效率降低80%严格使用数值类型 附录:性能优化参数参考 // keyword字段优化 // "category" 字段用于存储分类信息,将其类型设置为 "keyword",适用于精确匹配和聚合操作 "category": { "type": "keyword", // eager_global_ordinals 设置为 true 表示预加载全局序数 // 全局序数是 Elasticsearch 用于优化聚合操作的一种数据结构 // 预加载全局序数可以加快聚合查询的速度,因为在查询时无需再动态计算 // 但是,这会增加内存开销,尤其是在数据量较大时 // 因此,仅在需要频繁进行聚合操作且内存充足的情况下使用 "eager_global_ordinals": true }, // nested字段优化 // "specs" 字段用于存储产品规格等嵌套数据,将其类型设置为 "nested" // "nested" 类型允许在文档中嵌套子文档,并且可以对子文档进行独立的查询和聚合 "specs": { "type": "nested", // include_in_parent 设置为 true 表示允许父文档查询嵌套字段 // 这意味着在查询父文档时,可以同时匹配嵌套字段的条件 // 然而,这种方式会增加查询的复杂度和性能开销,因为需要在父文档和嵌套文档之间进行额外的关联操作 // 所以,使用时需要谨慎评估,仅在确实需要进行此类跨层级查询时启用 "include_in_parent": true }
标签:

【实战ES】实战Elasticsearch:快速上手与深度实践-2.1.2字段类型选择:keywordvstex由讯客互联人工智能栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“【实战ES】实战Elasticsearch:快速上手与深度实践-2.1.2字段类型选择:keywordvstex