#Elasticsearch探索:Suggester

让人想犯罪 __ 提交于 2020-12-10 18:21:39

 

简介

现代的搜索引擎,一般都会提供 Suggest as you type 的功能,帮助用户在输入搜索的过程中,进行自动补全或者纠错。通过协助用户输入更加精准的关键词,提高后续搜索阶段文档匹配的程度。在 google 上搜索,一开始会自动补全。当输入到一定长度,如因为单词拼写错误无法补全,就会开始提示相似的词或者句子。

1. Suggester API

搜索引擎中类似的功能,在 ES 中通过 Sugester API 实现的

  • 原理:将输入的文档分解为 Token,然后在索引的字段里查找相似的 Term 并返回
  • 根据不同的使用场景,ES 设计了 4 种类别的 Suggesters
    • Term
    • Phrase Suggester
    • Complete
    • Context Suggester

Term Suggester

Suggester 就是一种特殊类型的搜索。“text” 里是调用时候提供的文本,通常来自用户界面上用户输入的内容。用户输入的 “lucen” 是一个错误的拼写会到 指定的字段 “body” 上搜索,当无法搜索到结果时(missing),返回建议的词。

PUT /suggest_article/
{
  "mappings": {
    "_doc": {
      "properties": {
        "body": {
          "type": "text"
        }
      }
    }
  }
}

PUT suggest_article/_doc/1
{
  "body":"lucene is very cool"
}

"body":"Elasticsearch builds on top of lucene"
"body":"Elasticsearch rocks"
"body":"elastic is the company behind ELK stack"
"body":"Elk stack rocks"
"body":"elasticsearch is rock solid"

搜索:
POST suggest_article/_search
{
  "from": 0, 
  "size": 10,
  "query": {
    "match": {
      "body": "lucen rock"
    }
  },
  "suggest": {
    "term-suggestion": {
      "text": "lucen rock",
      "term": {
        "suggest_mode": "missing",  // popular  always
        "field": "body"
      }
    }
  }
}

结果:
{
  "took" : 38,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 1.1149852,
    "hits" : [
      {
        "_index" : "suggest_article",
        "_type" : "_doc",
        "_id" : "6",
        "_score" : 1.1149852,
        "_source" : {
          "body" : "elasticsearch is rock solid"
        }
      }
    ]
  },
  "suggest" : {
    "term-suggestion" : [
      {
        "text" : "lucen",
        "offset" : 0,
        "length" : 5,
        "options" : [
          {
            "text" : "lucene",
            "score" : 0.8,
            "freq" : 2
          }
        ]
      },
      {
        "text" : "rock",
        "offset" : 6,
        "length" : 4,
        "options" : [
          {
            "text" : "rocks",
            "score" : 0.75,
            "freq" : 2
          }
        ]
      }
    ]
  }
}

词条推荐器使用了Lucene的错拼检查器模块,该模块会根据给定词条的编辑距离(es使用了叫做Levenstein edit distance的算法,其核心思想就是一个词改动多少字符就可以和另外一个词一致),从索引中返回最大编辑距离不超过某个值的那些词条。比如说为了从mik得到mick,需要加入一个字母(也就是说需要至少要改动一次),所以这两个词的编辑距离就是1。

text:建议文本,建议文本是必需的选项,可以通过全局(多个建议器中查询相同的内容)或者按照单个建议器的格式来。
field:从field字段中获取候选建议的字段。这是一个必需的选项,需要全局设置或根据建议设置。
analyzer:用于分析建议文本的分析器。默认为建议字段的搜索分析器。
size:个建议文本标记返回的最大条目。
sort:定义如何根据建议文本术语对建议进行排序。它有两个可能的值。
score,先按分数排序,然后按文档频率排序,再按术语本身排序。
frequency,首先按文档频率排序,然后按相似性分数排序,然后按术语本身排序。也可以理解为按照流行度排序。
suggest_mode:控制建议的模式,有3个模式可选择。
  missing,仅为不在索引中的建议文本术语提供建议。这是默认值。
  popular,仅建议在比原始建议文本术语更多的文档中出现的建议。也就是说提供比原有输入词频更高的词条
  always,根据建议文本中的条款建议任何匹配的建议。说白了就是无论如何都会提供建议。
lowercase_terms:在文本分析之后降低建议文本术语的大小写。
min_word_length:建议文本术语必须具有的最小长度才能包含在内。默认为4.(旧名称min_word_len已弃用)。
shard_size:设置从每个单独分片中检索的最大建议数。

小结:term suggester首先将输入文本经过分析器(所以,分析结果由于采用的分析器不同而有所不同)分析,处理为单个词条,然后根据单个词条去提供建议,并不会考虑多个词条之间的关系。然后将每个词条的建议结果(有或没有)封装到options列表中。最后由推荐器统一返回。

Phrase Suggester

Phrase suggester在Term suggester的基础上,会考量多个term之间的关系,比如是否同时出现在索引的原文里,相邻程度,以及词频等等。

  • Suggeset Mode : missing,popular ,always
  • Max Errors: 最多可以拼错的 Terms 数
  • Condfidence : 限制返回结果数,默认为 1
POST suggest_article/_search
{
  "suggest": {
    "my-suggestion": {
      "text": "lucne and elasticsear rock",
      "phrase": {
        "field": "body",
        "max_errors":2, # 最多可以拼错的terms
        "confidence":0, # 限制返回的结果数,默认是1
        "direct_generator":[{
          "field":"body",
          "suggest_mode":"always"
        }],
        "highlight": {
          "pre_tag": "<em>",
          "post_tag": "</em>"
        }
      }
    }
  }
}

{
  "took" : 99,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "suggest" : {
    "my-suggestion" : [
      {
        "text" : "lucne and elasticsear rock",
        "offset" : 0,
        "length" : 26,
        "options" : [
          {
            "text" : "lucne and elasticsearch rocks",
            "highlighted" : "lucne and <em>elasticsearch rocks</em>",
            "score" : 0.12709484
          },
          {
            "text" : "lucne and elasticsearch rock",
            "highlighted" : "lucne and <em>elasticsearch</em> rock",
            "score" : 0.10422645
          },
          {
            "text" : "lucne and elasticsear rocks",
            "highlighted" : "lucne and elasticsear <em>rocks</em>",
            "score" : 0.10036137
          },
          {
            "text" : "lucne and elasticsear rock",
            "highlighted" : "lucne and elasticsear rock",
            "score" : 0.082303174
          },
          {
            "text" : "lucene and elasticsear rock",
            "highlighted" : "<em>lucene</em> and elasticsear rock",
            "score" : 0.030959692
          }
        ]
      }
    ]
  }
}

自定义高亮:
"pre_tag":"<b id='d1' class='t1' style='color:red;font-size:18px;'>",
"post_tag":"</b>"

注意:推荐器结果的高亮显示和查询结果高亮显示有些许区别,比如说,这里的自定义标签是pre_tag和post_tag而不是之前的pre_tags和post_tags

Completion Suggester

主要针对的应用场景就是"Auto Completion"。 此场景下用户每输入一个字符的时候,就需要即时发送一次查询请求到后端查找匹配项,在用户输入速度较高的情况下对后端响应速度要求比较苛刻。因此实现上它和前面两个Suggester采用了不同的数据结构,索引并非通过倒排来完成,而是将analyze过的数据编码成FST和索引一起存放。对于一个open状态的索引,FST会被ES整个装载到内存里的,进行前缀查找速度极快。但是FST只能用于前缀查找,这也是Completion Suggester的局限所在。

PUT /completion_article/
{
  "mappings": {
    "_doc": {
      "properties": {
        "body": {
          "type": "completion"
        }
      }
    }
  }
}

PUT completion_article/_doc/1
{
  "body":"lucene is very cool"
}

"body":"Elasticsearch builds on top of lucene"
"body":"Elasticsearch rocks"
"body":"elastic is the company behind ELK stack"
"body":"Elk stack rocks"
"body":"elasticsearch is rock solid"


POST completion_article/_search
{ "size": 0,
  "suggest": {
    "completion-suggest": {
      "prefix": "elastic i",
      "completion": {
        "field": "body"
      }
    }
  }
}

{
  "took" : 42,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "suggest" : {
    "completion-suggest" : [
      {
        "text" : "elastic i",
        "offset" : 0,
        "length" : 9,
        "options" : [
          {
            "text" : "elastic is the company behind ELK stack",
            "_index" : "completion_article",
            "_type" : "_doc",
            "_id" : "4",
            "_score" : 1.0,
            "_source" : {
              "body" : "elastic is the company behind ELK stack"
            }
          }
        ]
      }
    ]
  }
}

值得注意的一点是Completion Suggester在索引原始数据的时候也要经过analyze阶段,选用的analyzer不同,某些词可能会被转换或者某些词可能被去除,这些会影响FST编码结果,也会影响查找匹配的效果。

比如我们重新索引,设置索引的mapping,将analyzer更改为"english"




 

 

 

 

 

 

 

 

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!