Elasticsearch同义词配置

2021-09-16  本文已影响0人  郭彦超

很多情况下,我们希望在搜索时,有时能够使用一个词的同义词来进行补充搜索,这样我们能搜索出来更多相关的内容。这个场景可以通过 text analysis 来帮助我们生成同义词。那么在进行同义词搜索时,我们有如下的几种方案:

通过修改setting配置同义词

首先,我们来创建一个具有如下 anaylzer 及 mapping 的一个索引:


PUT myindex

{

  "settings": {

    "analysis": {

      "filter": {

        "my_synonyms": {

          "type": "synonym_graph",

          "synonyms": [

            "清新,可爱,动漫,粉色,浪漫"

          ]

        }

      },

      "analyzer": {

        "my_analyzer": {

          "type": "custom",

          "tokenizer": "ik_max_word",

          "filter":[

            "lowercase",

            "my_synonyms"

          ]

        }

      }

    }

  },

  "mappings": {

    "properties": {

      "title": {

        "type": "text",

        "analyzer": "ik_max_word",

        "search_analyzer": "my_analyzer"

      }

    }

  }

}

在上面,我们使用 synonym_graph 过滤器对 quey 时的词进行过滤。在这个过滤器中,我们把如下的一个词都视为同义词:

清新,可爱,动漫,粉色,浪漫

在mapping 中,我们定义了 search_analyzer 为 my_analyzer,也就是说在 query 时,它会对所有的词进行分词。但凡有任何一个词是 '清新,可爱,动漫,粉色,浪漫' 其中的一个,它都将被视为同义词。

我们首先来创建一个文档:


PUT myindex/_doc/1

{

  "title": "通用清新粉色高端医院美容企业春暖花开职等你来招聘"

}

运行上面的指令,我们将创建一个 title 为 '通用清新粉色高端医院美容企业春暖花开职等你来招聘' 的文档。

接下来,我们做如下的查询:


GET myindex/_search

{

  "query": {

    "match": {

      "title": "粉色"

    }

  }

}

那么显示的结果是:


{

  "took" : 256,

  "timed_out" : false,

  "_shards" : {

    "total" : 1,

    "successful" : 1,

    "skipped" : 0,

    "failed" : 0

  },

  "hits" : {

    "total" : {

      "value" : 1,

      "relation" : "eq"

    },

    "max_score" : 1.4384104,

    "hits" : [

      {

        "_index" : "myindex",

        "_type" : "_doc",

        "_id" : "1",

        "_score" : 1.4384104,

        "_source" : {

          "title" : "通用清新粉色高端医院美容企业春暖花开职等你来招聘"

        }

      }

    ]

  }

}

可能有人说了,这是因为上面的 title 里本身就含有 '粉色', 所以上面的结果证明不了什么。接下来,我们进行如下的搜索:


GET myindex/_search

{

  "query": {

    "match": {

      "title": "浪漫"

    }

  }

}

结果,我们可以发现,我们同样显示上面的搜索的结果。这个说明了这个同义词的搜索是成功的。

接下来,我们想通过搜索 '素雅' 也能搜索出'清新'来,那么我怎么做呢?

我们来执行如下的命令:


POST myindex/_close

PUT myindex/_settings

{

  "analysis": {

    "filter": {

      "my_synonyms": {

        "type": "synonym_graph",

        "synonyms": [

          "清新,素雅,可爱,动漫,粉色,浪漫"

        ]

      }

    },

    "analyzer": {

      "my_analyzer": {

        "type": "custom",

        "tokenizer": "standard",

        "filter": [

          "lowercase",

          "my_synonyms"

        ]

      }

    }

  }

}

POST myindex/_open

我们可以通过更新 setting 来实现这个。在上面请注意:当我们更新一个索引的 index 时,我们必须先把它关掉,等设置好后,在重新打开。否则会有错误。那么经过上面的修改后,我们重新运行如下的搜索:


GET myindex/_search

{

  "query": {

    "match": {

      "title": "素雅"

    }

  }

}

那么上面的搜索结果将会显示我们之前显示的结果。在这里 ‘素雅’ 也就是和之前的其它词都是同义词。

通过修改文件配置同义词

有人可能觉得上面在 settings 里配置太多的同义词很麻烦,而且关闭索引会影响线上查询(可以放到凌晨进行)。按照 Elastic 的官方文档,我们可以把所有的同义词放到一个文档中。首先,我们在 Elasticsearch 的 config 目录中,创建一个叫做 analysis 的子目录,然后创建一个叫做 synonyms.txt 的文档,而它的内容如下:

$ pwd

/Users/liuxg/elastic/elasticsearch-7.8.0/config/analysis

$ cat synonyms.txt

"清新,素雅,可爱,动漫,粉色,浪漫",

"elk, elastic stack"

在这里,我们多添加了一个 elk, elastic stack 的同义词。我们来创建一个新的索引:


PUT myindex1

{

  "settings": {

    "analysis": {

      "filter": {

        "my_synonyms": {

          "type": "synonym_graph",

          "synonyms_path": "analysis/synonyms.txt"

        }

      },

      "analyzer": {

        "my_analyzer": {

          "type": "custom",

          "tokenizer": "standard",

          "filter":[

            "lowercase",

            "my_synonyms"

          ]

        }

      }

    }

  },

  "mappings": {

    "properties": {

      "content": {

        "type": "text",

        "analyzer": "standard",

        "search_analyzer": "my_analyzer"

      }

    }

  }

}

运行完上的指令后,我们来创建一个文档:


PUT myindex1/_doc/1

{

  "content": "I love elastic stack"

}

然后我们做如下的搜索:

GET myindex1/_search

{

  "query": {

    "match": {

      "content": "elk"

    }

  }

}

上面的搜索结果显示:


{

  "took" : 451,

  "timed_out" : false,

  "_shards" : {

    "total" : 1,

    "successful" : 1,

    "skipped" : 0,

    "failed" : 0

  },

  "hits" : {

    "total" : {

      "value" : 1,

      "relation" : "eq"

    },

    "max_score" : 0.5753642,

    "hits" : [

      {

        "_index" : "myindex1",

        "_type" : "_doc",

        "_id" : "1",

        "_score" : 0.5753642,

        "_source" : {

          "content" : "I love elastic stack"

        }

      }

    ]

  }

}

显然,我可以看到搜索 elk,我们就可以搜索到含有 elastic stack 的文档。

在实际的使用中,如果我们更新 synonyms.txt 文件,那么,我们可以使用如下的 API 来进行更新:

POST myindex1/_reload_search_analyzers

总结

在上面,我们展示了两种方法进行同义词的查询。在实际的使用中,你可以根据自己的情况适当进行选择。当然,我们有可以把上面的两种方法进行同时并用。通过这两种方法,也有可能会造成搜索的精确度的问题。这个是你必须要想清楚的。这个就像我们撒网打鱼一样,把网撒大了,捞上来的也有可能不是我们想要的。
需要注意的是如果我们想在索引阶段就对同义词token进行索引的话,那么需要使用synonym分析器而不是synonym_graph

上一篇下一篇

猜你喜欢

热点阅读