Elasticsearch全文搜索引擎搭建:分词器配置与Query DSL查询实战

Elasticsearch索引与分片架构

Elasticsearch是基于Apache Lucene构建的分布式全文搜索引擎,通过倒排索引实现高效的文本检索。与传统关系型数据库的正向索引不同,倒排索引从词项出发映射到包含该词项的文档列表,使得全文检索的复杂度与文档总量无关,仅与匹配的词项数量相关。

Elasticsearch的核心概念映射:索引(Index)对应数据库,类型在7.x后已移除,文档(Document)对应行记录,字段(Field)对应列。索引在创建时可以设置分片数和副本数:

PUT /products
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1,
    "refresh_interval": "1s"
  }
}

number_of_shards设置主分片数量,索引创建后不可修改。number_of_replicas设置每个主分片的副本数,可以动态调整。分片数量应根据数据量预估,一般每个分片不超过50GB。refresh_interval控制索引刷新频率,值越小实时性越高但写入性能越低,批量写入时可临时设为-1(关闭自动刷新)以提升写入速度。

映射配置与字段类型选择

映射(Mapping)定义索引中文档的结构和字段类型。Elasticsearch支持动态映射和显式映射两种方式。生产环境推荐使用显式映射避免字段类型推断错误:

PUT /articles
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart"
      },
      "content": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "author": {
        "type": "keyword"
      },
      "publish_date": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss||epoch_millis"
      },
      "tags": {
        "type": "keyword"
      },
      "view_count": {
        "type": "integer"
      },
      "location": {
        "type": "geo_point"
      }
    }
  }
}

text类型会经过分词器处理后建立倒排索引,适合全文搜索。keyword类型不分词,整体作为一个词项索引,适合精确匹配、聚合和排序。日期字段支持多种格式,用||分隔多个可选格式。geo_point类型支持地理坐标查询。

中文分词器配置与IK插件

Elasticsearch内置的分词器对中文支持有限,中文场景需要安装IK Analysis插件。IK分词器提供两种分词模式:ik_max_word(最细粒度分词)和ik_smart(智能分词)。

# 安装IK插件
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.13.0/elasticsearch-analysis-ik-8.13.0.zip

# 配置自定义词典
# 编辑 config/analysis-ik/IKAnalyzer.cfg.xml
<properties>
    <entry key="ext_dict">custom_dict.dic</entry>
    <entry key="ext_stopwords">stop_words.dic</entry>
</properties>

# custom_dict.dic 每行一个自定义词
# 深度学习
# 人工智能
# 大语言模型

ik_max_word将文本拆分到最细粒度,尽可能多地产出词项,索引时使用可以增加召回率。ik_smart做粗粒度分词,适合搜索时使用以减少无关匹配。一种推荐做法是索引时用ik_max_word,搜索时用ik_smart,兼顾召回率和精确度。

验证分词效果:

GET /_analyze
{
  "analyzer": "ik_max_word",
  "text": "人工智能大模型应用开发实战"
}

# 返回分词结果
# 人工智能 / 人工 / 智能 / 大模型 / 大 / 模型 / 应用 / 开发 / 实战

Query DSL查询语法详解

Query DSL是Elasticsearch的JSON查询语言,分为叶子查询(Leaf Query)和复合查询(Compound Query)两类。

全文检索查询

POST /articles/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "人工智能 开发",
            "fields": ["title^3", "content"],
            "type": "best_fields",
            "tie_breaker": 0.3
          }
        }
      ],
      "filter": [
        { "term": { "tags": "技术" } },
        { "range": { "publish_date": { "gte": "2026-01-01" } } }
      ]
    }
  },
  "sort": [
    { "_score": "desc" },
    { "publish_date": "desc" }
  ],
  "from": 0,
  "size": 20,
  "highlight": {
    "fields": {
      "title": {},
      "content": { "fragment_size": 150, "number_of_fragments": 3 }
    }
  }
}

multi_match在多个字段上执行全文检索,title^3表示title字段权重为3倍,匹配优先级更高。type=best_fields取得分最高的字段作为文档得分,tie_breaker=0.3让其他匹配字段贡献30%的额外得分。filter子句不参与评分,利用缓存加速过滤,适合放置不需要打分的条件。highlight高亮匹配关键词,fragment_size控制片段长度。

精确查询与聚合

POST /articles/_search
{
  "size": 0,
  "query": {
    "bool": {
      "filter": [
        { "terms": { "author": ["张三", "李四"] } }
      ]
    }
  },
  "aggs": {
    "articles_by_tag": {
      "terms": { "field": "tags", "size": 10 },
      "aggs": {
        "avg_views": {
          "avg": { "field": "view_count" }
        },
        "date_histogram": {
          "date_histogram": {
            "field": "publish_date",
            "calendar_interval": "month"
          }
        }
      }
    }
  }
}

size=0表示不返回文档,只返回聚合结果。terms聚合按标签分组并统计文档数,嵌套的avg聚合计算每组平均浏览量,date_histogram按月分桶展示发布趋势。嵌套聚合可以多层组合,实现复杂的数据分析。

索引别名与零停机重建

当需要修改映射或调整分片数时,索引需要重建。通过别名(Alias)机制可以实现零停机索引切换:

# 1. 为原索引创建别名
POST /_aliases
{
  "actions": [
    { "add": { "index": "articles_v1", "alias": "articles" } }
  ]
}

# 2. 应用通过别名读写数据
POST /articles/_doc
{ "title": "新文章", "content": "内容" }

# 3. 创建新索引v2(新mapping)
PUT /articles_v2 { "mappings": { ... } }

# 4. 使用reindex迁移数据
POST /_reindex
{
  "source": { "index": "articles_v1" },
  "dest": { "index": "articles_v2" }
}

# 5. 原子切换别名
POST /_aliases
{
  "actions": [
    { "remove": { "index": "articles_v1", "alias": "articles" } },
    { "add": { "index": "articles_v2", "alias": "articles" } }
  ]
}

# 6. 删除旧索引
DELETE /articles_v1

别名切换是原子操作,切换瞬间所有读写请求自动指向新索引。reindex过程中应用继续通过别名读写旧索引,切换后无缝导向新索引。对于大规模数据reindex,可以配合sliced scrolling并行处理加速迁移。

搜索性能调优实践

Elasticsearch性能优化需要从索引设计和查询优化两方面入手。索引设计阶段,text字段如果不需要排序和聚合,不要开启fielddata,使用keyword子字段替代。对不参与搜索的字段设置”index”: false减少索引体积。

"description": {
    "type": "text",
    "fields": {
        "raw": { "type": "keyword" }
    },
    "index_options": "offsets"
}

fields.raw子字段为keyword类型,可用于排序和聚合。index_options: offsets在需要高亮时存储偏移量信息。查询阶段,使用filter替代must进行条件过滤,filter结果会被缓存。避免使用script查询和wildcard前缀通配查询,这些查询无法利用倒排索引,性能极差。对于分页查询,from + size方式在深翻页时性能下降严重,推荐使用search_after基于排序值的游标分页。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/elasticsearch-quan-wen-sou-suo-yin-qing-da-jian-fen-ci-qi/

(0)
小编小编
上一篇 3小时前
下一篇 3小时前

相关推荐