倒排索引结构:Term Dictionary与Posting List
Elasticsearch是基于Apache Lucene构建的分布式全文检索引擎。与MySQL等关系型数据库使用B+树正排索引不同,Elasticsearch的核心数据结构是倒排索引(Inverted Index),通过词项到文档的映射实现快速全文检索。理解倒排索引的工作原理,是数据库运维和Elasticsearch性能调优的基础。
倒排索引由两部分组成:Term Dictionary(词典)和Posting List(倒排链表)。Term Dictionary存储所有经过分词处理的唯一词项,Posting List记录每个词项出现在哪些文档中以及出现的位置信息。
以文档集为例:文档1包含”分布式系统设计”,文档2包含”分布式架构与优化”。经中文分词后,Term Dictionary包含:分布式、系统、设计、架构、与、优化。其中”分布式”对应的Posting List为[1, 2],表示该词出现在文档1和文档2中。
// 倒排索引结构示意
Term Dictionary:
分布式 -> Posting List: [doc1, doc2]
系统 -> Posting List: [doc1]
设计 -> Posting List: [doc1]
架构 -> Posting List: [doc2]
优化 -> Posting List: [doc2]
// Posting List内部结构
"分布式"的Posting List:
DocID: 1, TF: 1, Positions: [0], Offset: [0-3]
DocID: 2, TF: 1, Positions: [0], Offset: [0-3]
Posting List中每个条目记录文档ID(DocID)、词频(TF)、出现位置(Positions)和偏移量(Offset)。位置信息支持短语查询,偏移量用于搜索结果高亮。Elasticsearch使用FOR(Frame of Reference)编码压缩Posting List,大幅减少内存占用。
Term Dictionary在内存中使用FST(Finite State Transducer)数据结构存储。FST将词典压缩为有向无环图,共享公共前缀和后缀。10亿个词项的词典经FST压缩后可能只占用几百MB内存,这是Elasticsearch能在内存中保存大量词典的关键。
分词器配置与中文分析器IK
分词器(Analyzer)决定文本如何被切分为词项,直接影响搜索的召回率和准确率。Elasticsearch内置了standard、simple、whitespace等分析器,但对中文支持有限。IK分词器是Elasticsearch中文全文检索的事实标准:
# 安装IK分词器
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.15.0/elasticsearch-analysis-ik-8.15.0.zip
# 自定义分词器配置
PUT /articles
{
"settings": {
"analysis": {
"analyzer": {
"ik_smart_analyzer": {
"type": "custom",
"tokenizer": "ik_smart",
"filter": ["lowercase", "stop_filter"]
},
"ik_max_word_analyzer": {
"type": "custom",
"tokenizer": "ik_max_word",
"filter": ["lowercase"]
}
},
"filter": {
"stop_filter": {
"type": "stop",
"stopwords": ["的", "了", "是", "在"]
}
}
}
}
}
IK提供两种分词模式:ik_smart做粗粒度切分,适合搜索查询;ik_max_word做细粒度切分,适合索引阶段。索引时使用ik_max_word最大化召回率,查询时使用ik_smart提高精确度。这种”索引用max_word、搜索用smart”的组合策略是中文搜索的最佳实践。
自定义词典通过IK配置文件ext.dic添加领域专有词汇。例如电商场景需要添加”碎屏险”、”以旧换新”等未登录词,否则IK会将”碎屏险”切分为”碎”和”屏险”,导致搜索不到。
Mapping映射与字段类型选择
Mapping定义索引的字段结构和类型,类似于数据库的表结构DDL。字段类型选择直接影响存储空间和查询性能:
PUT /products
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word_analyzer",
"search_analyzer": "ik_smart_analyzer",
"fields": {
"keyword": { "type": "keyword" }
}
},
"description": {
"type": "text",
"analyzer": "ik_max_word_analyzer"
},
"price": {
"type": "scaled_float",
"scaling_factor": 100
},
"tags": {
"type": "keyword"
},
"create_time": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||epoch_millis"
},
"location": {
"type": "geo_point"
},
"status": {
"type": "integer"
}
}
}
}
text类型经过分词建立倒排索引,适合全文检索。keyword类型不分词,整体作为一个词项索引,用于精确匹配、排序和聚合。一个字段同时需要全文检索和精确匹配时,使用fields配置多类型:title字段同时有text类型的分词索引和keyword类型的精确索引。
数值类型优先选择scaled_float而非double,scaled_float将浮点数乘以scaling_factor后存为整数,压缩效果更好且计算更快。geo_point类型支持地理位置查询,如”查找5公里范围内的门店”。
dynamic mapping虽然方便,但在生产环境应禁用或设为strict,避免错误格式的文档自动创建字段导致mapping膨胀。设置”dynamic”: “strict”后,包含未定义字段的文档会被直接拒绝。
全文检索查询DSL与高亮显示
Elasticsearch的Query DSL提供了丰富的查询类型。全文检索常用match和multi_match查询:
GET /products/_search
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "分布式架构设计",
"fields": ["title^3", "description"],
"type": "best_fields",
"tie_breaker": 0.3
}
}
],
"filter": [
{ "range": { "price": { "gte": 50, "lte": 500 } } },
{ "term": { "status": 1 } }
]
}
},
"highlight": {
"fields": {
"title": {
"pre_tags": ["<em class='hl'>"],
"post_tags": ["</em>"],
"number_of_fragments": 0
},
"description": {
"fragment_size": 100,
"number_of_fragments": 3
}
}
},
"sort": [
{ "_score": "desc" },
{ "create_time": "desc" }
],
"from": 0,
"size": 20
}
multi_match的best_fields策略取匹配度最高字段的分数作为该文档的相关性分数,title^3表示title字段的权重是description的3倍。tie_breaker=0.3表示其他匹配字段的分数按30%权重计入总分。filter子句不参与相关性评分,用于条件过滤,查询结果会被缓存。
highlight利用Posting List中的Offset信息定位匹配位置,在匹配文本前后插入标签。number_of_fragments=0表示返回整个字段内容,而非截取片段。
索引性能优化与分片策略
分片数量在索引创建后无法修改(除非reindex),合理规划分片数是Elasticsearch集群规划的关键。单个分片建议存储量不超过50GB,分片数按”预估数据量 / 50GB”计算,向上取整。分片过多导致每个分片资源开销增加,聚合查询需要在所有分片间做scatter-gather;分片过少无法利用多节点并行能力。
写入性能优化方面,批量写入使用bulk API,单次bulk请求包含1000-5000个文档。refresh_interval在批量导入阶段可设为-1(禁用刷新),导入完成后再恢复。routing参数按业务维度路由文档到同一分片,减少聚合查询的跨分片开销。对于时序数据使用索引模板(index template)配合ILM自动管理索引生命周期。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/elasticsearch-dao-pai-suo-yin-yuan-li-yu-fen-ci-qi-pei-zhi/