ElasticSearch应用篇-搜索增强

ES有一些非常强大的能力,例如:根据用户搜索的时候,也可以搜索同义词,也可以基于语义进行分词,返回最最适合的结果,ElasticSearch是如何实现这种能力的呢?

一、ES搜索与Analyzer

1.ES搜索过程

为了搞清楚这个问题,我们需要提前搞清楚ES搜索的过程,ElasticSearch的这个能力是由Analyzer来实现的。ES中一个Analyzer处理搜索的过程如下:
在这里插入图片描述

从这个处理流程可以看到,在token filter会为词条增加一些同义词,这就是ES可以支持同义词搜索的原因所在。

2.Analyzer(解析器)

1)Analyzer组成

Analyzer由0个或多个char_filter,1个tokenizer,0个或多个token filter组成。

char_filter用于分词前对原搜索的句子进行处理,如去除HTML标签。

tokenizer用于将搜索的句子分成多个词组,如将一段话根据分词器或者空格拆分成多个词等。

token filter用于处理tokenizer输出的词组,常见的操作有:删除、修改增加某些词,例如:去掉a、the词组,大写转小写,增加同义词。

Analyzer的配置说明:

处理器 描述
tokenizer 通用的或者注册的tokenizer.
filter 通用的或者注册的 token filters.
char_filter 通用的或者注册的 character filters.
position_increment_gap 距离查询时,最大允许查询的距离,默认是100

2)Analyzer与search_analyzer的区别

ES中主要有两种情况会用分析器:一是插入文档时,将text类型的字段做分词然后插入倒排索引,二是查询时,先对要查询的text类型的输入做分词,再去倒排索引搜索。使用的具体规则是:创建索引时,只看字段有没有定义analyzer,有定义的话就用定义的,没定义就用ES预设的;在查询时,先看字段有没有定义search_analyzer,如果没有定义,去看有没有analyzer,再没有定义才会去使用ES预设的。

2.CharFilter

elasticearch只提供了三种字符过滤器:

1)HTML Strip Char Filter(HTML字符过滤器)

可以去除HTML标签,例如将<p>I’<br>Love</br> cat</p>转变为:I Love cat。

示例代码:

{
    "tokenizer":"keyword",

    "char_filter":[

        "html_strip"

    ],

    "text":"&lt;p&gt;I' &lt;br&gt;Love&lt;/br&gt; cat&lt;/p&gt;"
}

结果为:

{
    "tokenizer":"keyword",

    "char_filter":[

        "html_strip"

    ],

    "text":"I Love cat"
}

2)Mapping Char Filter(映射字符过滤器)

可以替换查询字符串的内容,例如将“特朗普”转变为:TTT。

{
    "settings":{

        "analysis":{

            "analyzer":{

                "my_analyzer":{

                    "tokenizer":"keyword",

                    "char_filter":[

                        "my_char_filter"

                    ]

                }

            },

            "char_filter":{

                "my_char_filter":{

                    "type":"mapping",

                    "mappings":[

                        "特朗普=&gt; TTT "

                    ]

                }

            }

        }

    }
}

创建索引或者搜索的时候将会将“特朗普”转换成“TTT”。

3)Pattern Replace Char Filter(模式替换过滤器)

可以使用正则表达式匹配并替换字符串中的字符。具体能力看正则表达式,具体示例省略。

3.tokenizer

接下来介绍几种常见的分词器。

1)standard tokenizer (标准分词器)

标准类型的tokenizer,对英语等欧洲语言非常友好,支持Unicode。属性:

属性 说明
max_token_length 最大的token集合,即经过tokenizer过后得到的结果集的最大值。如果token的长度超过了设置的长度,将会继续分,默认255

2)NGram Tokenizer(连词分词器)

如果词的长度大于最短词长度则分词,依次分成最小长度递进到最大长度的词。例如:min_gram=2, max_gram=3下王者荣耀的分词结果为:王者、王者荣、者荣耀、荣耀。

属性:

设置 说明 Default value
min_gram 分词后词语的最小长度 1
max_gram 分词后词语的最大长度 2
token_chars 设置分词的形式 [](Keep all characters)letter(单词),digit(数字),whitespace(空白),punctuation(标点,如!),symbol(符号,如&)

3)Edge NGram tokenizer(自动补全)

和NGramTokenizer非常相似,不过支持自动补全功能。

二、中文分词

1.场景

假设ik_demo索引中有以下记录,如下表格所示

_index _type _id _score message
ik_demo _doc 1 1 我爱中华人民共和国
ik_demo _doc 2 1 我来自中国湖北枣阳

按照这个示例,“国”在不同上下文中是不同的,第二句“中国”是一个词,单独搜索“国”的时候应该返回此记录。

2.elasticsearch-analysis-ik

elasticsearch需要先安装分词器才能支持分词功能,这里使用的是elasticsearch-analysis-ik,地址:https://github.com/medcl/elasticsearch-analysis-ik

安装ik:

./bin/elasticsearch-plugin installhttps://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.3.2/elasticsearch-analysis-ik-7.3.2.zip

注意:7.3.2为使用的elasticsearch版本;

3.设置mapping

curl -XPUT 'http://localhost:9200/ik_demo/_mapping?pretty' -H 'Content-Type: application/json' -d '
{
    "properties" : {

        "message" : {

            "type" : "text",

            "analyzer" : "ik_max_word",

            "search_analyzer" : "ik_smart",

            "fields" : {

              "keyword" : {

                "type" : "keyword",

                "ignore_above" : 256

              }

            }

        }

    }
}'

4.添加数据

curl -XPUT 'http://localhost:9200/ik_demo/_doc/1?pretty' -H 'Content-Type: application/json' -d '
{ "message": "我爱中华人民共和国"}'

curl -XPUT 'http://localhost:9200/ik_demo/_doc/2?pretty' -H 'Content-Type: application/json' -d '
{"message": "我来自中国湖北枣阳"}'

5.搜索

分词过程中会将中国作为一个词,所以单独搜索“国”的时候,将无法搜索到带有“我来自中国湖北枣阳”这个记录。

curl -XGET 'http://localhost:9200/ik_demo/_search?pretty=true' -H 'Content-Type: application/json' -d '
{"query":{"match":{"message":"国"}}}'

返回结果:

{
    "took":3,

    "timed_out":false,

    "_shards":{

        "total":5,

        "successful":5,

        "skipped":0,

        "failed":0

    },

    "hits":{

        "total":{

            "value":1,

            "relation":"eq"

        },

        "max_score":0.2876821,

        "hits":[

            {

                "_index":"ik_demo",

                "_type":"_doc",

                "_id":"1",

                "_score":0.2876821,

                "_source":{

                    "message":"我爱中华人民共和国"

                }

            }

        ]

    }
}

这里仅简单介绍使用,具体分词内容可以参考:https://github.com/medcl/elasticsearch-analysis-ik

三、近义词、同义词搜索

1.场景

假设synonym_demo索引中有以下记录,如下表格所示

_index _type _id _score message
synonym_demo _doc 1 1 我喜欢猫
synonym_demo _doc 2 1 我喜欢cat
synonym_demo _doc 3 1 我喜欢狗

猫和cat其实是同一个意思,如果想搜索猫的时候,将【1、2】记录都搜索出来,应该如何处理呢?

2.elasticsearch-dynamic-synonym

安装同义词插件,这里使用的是elasticsearch-dynamic-synonym,地址:https://github.com/ginobefun/elasticsearch-dynamic-synonym

安装:

git clone https://github.com/ginobefun/elasticsearch-dynamic-synonym.git

mvn clean install -DskipTests

将target/releases/elasticsearch-dynamic-synonym-<version>.zip解压到ES_HOME/plugin/dynamic-synonym目录中。

修改plugin-descriptor.properties,注释掉site、jvm、isolated,并且将elasticsearch.version改成elasticsearch的版本。如下所示:

#site=${elasticsearch.plugin.site}

#jvm=true

#isolated=${elasticsearch.plugin.isolated}

elasticsearch.version=7.3.2

3.创建索引

在ES_HOME/config/analysis/synonyms.txt中添加同义词:猫,cat

创建索引:

curl -XPUT 'http://localhost:9200/synonym_demo?pretty' -H 'Content-Type: application/json' -d '
  {
  "settings": {

      "analysis": {

        "analyzer": {

          "my_dynamic_synonym": {

            "type": "custom",

            "tokenizer": "whitespace",

            "filter": ["my_synonym"]

          }

        },

        "filter": {

          "my_synonym" : {

                  "type" : "synonym",

                  "expand": true,

                  "ignore_case": true,

                  "synonyms_path" : "analysis/synonyms.txt"

          }

        }

      }

  },

  "mappings":{

      "properties" : {

          "message" : {

              "type" : "text",

              "analyzer" : "ik_max_word",

              "search_analyzer" : "my_dynamic_synonym",

              "fields" : {

                "keyword" : {

                  "type" : "keyword",

                  "ignore_above" : 256

                }

              }

          }

      }

  }
  }'

4.添加数据

curl -XPUT 'http://localhost:9200/synonym_demo/_doc/1?pretty' -H 'Content-Type: application/json' -d '{ "message": "我喜欢猫" }'
curl -XPUT 'http://localhost:9200/synonym_demo/_doc/2?pretty' -H 'Content-Type: application/json' -d '{  "message": "我喜欢cat" }'
curl -XPUT 'http://localhost:9200/synonym_demo/_doc/3?pretty' -H 'Content-Type: application/json' -d '{ "message": "我喜欢狗"}'

5.搜索

因为猫、cat是同义词,所以搜索cat的时候,猫也应该会返回。

curl -XGET 'http://localhost:9200/synonym_demo/_search?pretty=true' -H 'Content-Type: application/json' -d '
{"query":{"match":{"message":"cat"}}}'

返回结果:

{
    "took" : 3,

    "timed_out" : false,

    "_shards" : {

        "total" : 1,

        "successful" : 1,

        "skipped" : 0,

        "failed" : 0

    },

    "hits" : {

        "total" : {

            "value" : 2,

            "relation" : "eq"

        },

        "max_score" : 1.2039728,

        "hits" : [

            {

                "_index" : "synonym_demo",

                "_type" : "_doc",

                "_id" : "1",

                "_score" : 1.2039728,

                "_source" : {

                    "message" : "我喜欢猫"

                }

            },

            {

                "_index" : "synonym_demo",

                "_type" : "_doc",

                "_id" : "2",

                "_score" : 1.2039728,

                "_source" : {

                    "message" : "我喜欢cat"

                }

            }

        ]

    }
}

四、参考文档

search_analyzer:

https://www.elastic.co/guide/en/elasticsearch/reference/current/search-analyzer.html

Custom Analyzer:

https://www.elastic.co/guide/en/elasticsearch/reference/2.1/analysis-custom-analyzer.html

elasticsearch之内置字符过滤器

https://www.cnblogs.com/Neeo/articles/10613612.html

elasticsearch-dynamic-synonym:

https://github.com/ginobefun/elasticsearch-dynamic-synonym

猜你喜欢

转载自blog.csdn.net/wuzhengfei1112/article/details/111403026