倒排索引(Inverted Index)是现代搜索引擎如Elasticsearch和Lucene实现高速文本检索的核心数据结构。与传统的正排索引不同,倒排索引采用了一种革命性的"以词找文档"的映射方式。
正排索引就像一本书的目录,你需要先找到具体的章节,然后才能看到里面的内容。在数据库领域,这相当于全表扫描——必须遍历整张表才能找到包含特定关键词的记录。
倒排索引则像书本末尾的索引表,直接告诉你哪些页面包含某个特定词汇。这种结构转换带来了质的飞跃:
当文档进入系统时,会经历以下标准化处理流程:
实际存储结构示例:
code复制"搜索" → [doc1, doc3, doc5]
"引擎" → [doc1, doc2, doc5]
搜索"搜索引擎"时的处理流程:
提示:倒排索引之所以快,是因为它把耗时的文本匹配转换为了高效的数字集合运算。
在Elasticsearch中,数据组织采用层级结构:
字段(Field):最小数据单元,相当于数据库中的列
文档(Document):JSON格式的基本数据单位,相当于表中的一行
json复制{
"title": "Elasticsearch指南",
"author": "张三",
"publish_date": "2023-01-15",
"content": "这是一篇关于ES的详细教程..."
}
索引(Index):文档的集合,类似数据库中的表
三者关系图示:
code复制索引(user_index)
│
├─ 文档(id=1)
│ ├─ 字段(username: "john")
│ └─ 字段(age: 28)
│
└─ 文档(id=2)
├─ 字段(username: "mary")
└─ 字段(age: 32)
Mapping定义了索引的结构约束,常见配置项:
json复制{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"price": {
"type": "double"
},
"tags": {
"type": "keyword"
}
}
}
}
关键属性说明:
type:字段数据类型
index:是否创建索引(默认true)
analyzer:指定分词器(如ik_smart)
fields:多字段特性,允许一个字段以不同方式索引
Elasticsearch原生分词器对中文支持有限,IK分词器是中文场景的首选解决方案。
两种核心模式对比:
| 模式 | 切分粒度 | 适用场景 | 示例输入→输出 |
|---|---|---|---|
| ik_smart | 粗粒度 | 精准搜索 | "中华人民共和国"→["中华人民共和国"] |
| ik_max_word | 细粒度 | 高召回率 | "中华人民共和国"→["中华","中华人民","中华人民共和国","人民","共和国"] |
通过修改IK配置扩展专业词汇:
config/IKAnalyzer.cfg.xml中添加:xml复制<entry key="ext_dict">custom/mydict.dic</entry>
<entry key="ext_stopwords">custom/mystop.dic</entry>
code复制区块链
人工智能
机器学习
code复制的
了
是
注意:词典文件需保存为UTF-8无BOM格式,修改后需重启ES或重建索引生效。
match查询:
示例:
json复制{
"query": {
"match": {
"content": "搜索引擎原理"
}
}
}
实际执行:先分词为["搜索","引擎","原理"],然后分别查询
term查询:
示例:
json复制{
"query": {
"term": {
"status": {
"value": "published"
}
}
}
}
bool查询是组合多个条件的瑞士军刀:
json复制{
"query": {
"bool": {
"must": [
{ "match": { "title": "手机" } }
],
"filter": [
{ "term": { "brand": "华为" } },
{ "range": { "price": { "gte": 2000, "lte": 5000 } } }
],
"must_not": [
{ "term": { "quality": "二手" } }
],
"should": [
{ "term": { "seller": "旗舰店" } }
],
"minimum_should_match": 1
}
}
}
各子句作用:
使用from+size参数实现传统分页:
json复制{
"query": { "match_all": {} },
"from": 20,
"size": 10,
"sort": [
{ "publish_date": "desc" }
]
}
限制:
from + size ≤ 10000(可通过index.max_result_window调整)方案一:search_after + PIT
json复制// 1. 创建PIT(有效期5分钟)
POST /my_index/_pit?keep_alive=5m
// 2. 首次查询
{
"size": 10,
"query": {...},
"pit": {
"id": "pit_id_value",
"keep_alive": "5m"
},
"sort": [
{"price": "asc"},
{"_id": "desc"}
]
}
// 3. 后续查询(使用上次结果的最后一个sort值)
{
"size": 10,
"query": {...},
"pit": {...},
"sort": [...],
"search_after": [1999, "doc_id_xyz"]
}
优势:
方案二:Scroll API(适合离线导出)
json复制// 初始化
POST /my_index/_search?scroll=5m
{
"size": 100,
"query": {...}
}
// 后续获取
POST /_search/scroll
{
"scroll": "5m",
"scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAA..."
}
特点:
Elasticsearch默认使用BM25算法计算_score,影响因素包括:
1. 指定排序字段:
json复制{
"query": {...},
"sort": [
{ "price": { "order": "asc" }},
{ "_score": { "order": "desc" }}
]
}
2. 使用function_score干预评分:
json复制{
"query": {
"function_score": {
"query": { "match": { "title": "手机" } },
"functions": [
{
"filter": { "term": { "brand": "华为" } },
"weight": 2
},
{
"field_value_factor": {
"field": "sales",
"factor": 1.2,
"modifier": "sqrt"
}
}
],
"boost_mode": "multiply"
}
}
}
3. 字段级boost设置:
json复制{
"query": {
"multi_match": {
"query": "智能手机",
"fields": ["title^3", "description"],
"type": "best_fields"
}
}
}
冷热数据分离:
基于时间滚动的索引:
合理的分片数量:
避免通配符查询:
*开头的wildcard查询合理使用聚合:
cardinality而非termsexecution_hint: map优化内存使用缓存策略:
request_cache: true关键监控指标:
定期维护操作:
json复制{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "智能手机 5G",
"fields": ["name^3", "description^2", "tags"],
"operator": "and"
}
}
],
"filter": [
{ "term": { "status": "on_sale" } },
{ "range": { "price": { "gte": 1000, "lte": 5000 } } },
{ "geo_distance": { "distance": "10km", "location": "31.23,121.47" } }
],
"should": [
{ "term": { "is_premium": true } },
{ "term": { "free_shipping": true } }
]
}
},
"sort": [
{ "_score": "desc" },
{ "sales_volume": "desc" }
],
"aggs": {
"brands": {
"terms": { "field": "brand" }
},
"price_ranges": {
"range": {
"field": "price",
"ranges": [
{ "to": 1000 },
{ "from": 1000, "to": 3000 },
{ "from": 3000 }
]
}
}
}
}
json复制// 错误日志统计
{
"query": {
"bool": {
"filter": [
{ "range": { "@timestamp": { "gte": "now-1h" } } },
{ "match": { "level": "ERROR" } }
]
}
},
"aggs": {
"error_by_service": {
"terms": { "field": "service" },
"aggs": {
"error_types": {
"terms": { "field": "error_code" }
}
}
},
"errors_over_time": {
"date_histogram": {
"field": "@timestamp",
"calendar_interval": "5m"
}
}
}
}
类型(type)变化:
集群协调变更:
查询语法调整:
安全默认启用:
Java客户端变更:
新特性适配:
症状:搜索响应慢,CPU使用率高
排查步骤:
json复制PUT /_cluster/settings
{
"transient": {
"logger.org.elasticsearch.search": "DEBUG"
}
}
json复制{
"profile": true,
"query": {...}
}
症状:索引速率下降,bulk请求失败
解决方案:
json复制PUT /my_index/_settings
{
"index.refresh_interval": "30s"
}
json复制{
"indices.memory.index_buffer_size": "20%"
}
症状:频繁GC,节点离开集群
处理方案:
json复制{
"indices.fielddata.cache.size": "30%"
}
json复制GET /_nodes/hot_threads
在实际生产环境中部署Elasticsearch集群时,有几个关键点值得特别注意:
硬件配置:
索引生命周期管理:
json复制PUT _ilm/policy/logs_policy
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": {
"max_size": "50GB",
"max_age": "30d"
}
}
},
"delete": {
"min_age": "365d",
"actions": {
"delete": {}
}
}
}
}
}
安全实践:
容量规划:
在最近的一个电商搜索系统优化项目中,我们通过以下措施将查询延迟从平均450ms降低到120ms:
这些经验表明,合理的索引设计和查询优化能带来显著的性能提升。