You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Elasticsearch中如何利用索引内synonyms字段实现同义词搜索

实现单文档自定义同义词替代外部文件方案

Elasticsearch的全局同义词分析器是索引级别的全局配置,无法直接引用单条文档的字段值,所以要实现每条文档自定义同义词的需求,得从查询阶段动态处理入手,以下是具体实现步骤:

1. 创建基础索引

不需要配置同义词分析器,只需定义字段类型,注意开启synonyms字段的fielddata方便后续脚本处理:

PUT /test_synonym
{
  "mappings": {
    "properties": {
      "name": { "type": "text" },
      "description": { "type": "text" },
      "synonyms": { "type": "text", "fielddata": true }
    }
  }
}

2. 插入批量数据

先修正你原数据里重复_id的问题(会导致后插入的数据覆盖前一条),然后执行批量插入:

POST /test_synonym/_bulk
{"index":{"_index":"test_synonym","_id":"1"}}
{"name":"test one two","description":"test numbers","synonyms": "tot, number"}
{"index":{"_index":"test_synonym","_id":"2"}}
{"name":"test coding","description":"test coding","synonyms": "tc, program"}

3. 方法一:查询时用脚本扩展同义词条件

当搜索某个词时,通过bool查询同时匹配原始字段和同义词组:

GET /test_synonym/_search
{
  "query": {
    "bool": {
      "should": [
        // 匹配name/description里的查询词
        { "multi_match": { "query": "tot", "fields": ["name", "description"] } },
        // 匹配同义词组包含查询词的文档(实现同义词反向匹配)
        {
          "script": {
            "script": {
              "source": """
                def syns = doc['synonyms'].value.split(',');
                for (def syn : syns) {
                  if (syn.trim() == params.query_term) {
                    return true;
                  }
                }
                return false;
              """,
              "params": { "query_term": "tot" }
            }
          }
        }
      ]
    }
  }
}

4. 方法二:用Runtime字段预拆分同义词数组

提前定义一个Runtime字段,把逗号分隔的synonyms拆成数组,后续查询更简洁:

PUT /test_synonym/_mapping
{
  "runtime": {
    "synonym_list": {
      "type": "keyword",
      "script": """
        def synArray = new ArrayList();
        if (doc['synonyms'].size() > 0) {
          def syns = doc['synonyms'].value.split(',');
          for (def syn : syns) {
            synArray.add(syn.trim());
          }
        }
        emit(synArray);
      """
    }
  }
}

之后查询时直接用terms匹配同义词数组,结合原始字段查询:

GET /test_synonym/_search
{
  "query": {
    "bool": {
      "should": [
        { "multi_match": { "query": "program", "fields": ["name", "description"] } },
        { "terms": { "synonym_list": ["program"] } }
      ]
    }
  }
}

5. 进阶:实现双向同义词匹配(类似分析器替换效果)

如果要实现“搜索同义词组里的任意词,都能匹配到文档的原始字段内容”,可以用脚本把同义词组的所有词都作为查询条件:

GET /test_synonym/_search
{
  "query": {
    "bool": {
      "should": [
        { "multi_match": { "query": "tot", "fields": ["name", "description"] } },
        {
          "script": {
            "script": {
              "source": """
                def syns = doc['synonyms'].value.split(',');
                def queryTerms = new ArrayList();
                queryTerms.add(params.query_term);
                for (def syn : syns) {
                  queryTerms.add(syn.trim());
                }
                return doc['name'].value.containsAny(queryTerms) || doc['description'].value.containsAny(queryTerms);
              """,
              "params": { "query_term": "tot" }
            }
          }
        }
      ]
    }
  }
}

注意事项

  • 别用索引时的同义词分析器:全局分析器没法引用单文档字段,必须在查询阶段处理。
  • 性能优化:如果数据量较大,建议索引时就把synonyms存成数组类型(比如["tot", "number"]),减少脚本拆分的开销。

内容的提问来源于stack exchange,提问作者Narayan bhat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 15:32:20