使用ElasticSearch模拟SQL LIKE搜索

我只是从ElasticSearch开始,然后尝试基于它来实现自动完成功能。

我有一个autocomplete带有citytype 字段的索引string。这是存储在该索引中的文档的示例:

{  

"_index":"autocomplete_1435797593949",

"_type":"listing",

"_id":"40716",

"_source":{

"city":"Rome",

"tags":[

"listings"

]

}

}

分析配置如下所示:

{  

"analyzer":{

"autocomplete_term":{

"tokenizer":"autocomplete_edge",

"filter":[

"lowercase"

]

},

"autocomplete_search":{

"tokenizer":"keyword",

"filter":[

"lowercase"

]

}

},

"tokenizer":{

"autocomplete_edge":{

"type":"nGram",

"min_gram":1,

"max_gram":100

}

}

}

映射:

{  

"autocomplete_1435795884170":{

"mappings":{

"listing":{

"properties":{

"city":{

"type":"string",

"analyzer":"autocomplete_term"

},

}

}

}

}

}

我将以下查询发送到ES:

{  

"query":{

"multi_match":{

"query":"Rio",

"analyzer":"autocomplete_search",

"fields":[

"city"

]

}

}

}

结果,我得到以下信息:

{  

"took":2,

"timed_out":false,

"_shards":{

"total":5,

"successful":5,

"failed":0

},

"hits":{

"total":1,

"max_score":2.7742395,

"hits":[

{

"_index":"autocomplete_1435795884170",

"_type":"listing",

"_id":"53581",

"_score":2.7742395,

"_source":{

"city":"Rio",

"tags":[

"listings"

]

}

}

]

}

}

在大多数情况下,它是有效的。city = "Rio"在用户必须实际键入整个单词之前,它确实找到了带有的文档("Ri"足够了)。

这就是我的问题。我也希望它返回"Rio de Janeiro"。要获取"Rio de Janeiro",我需要发送以下查询:

  {  

"query":{

"multi_match":{

"query":"Rio d",

"analyzer":"standard",

"fields":[

"city"

]

}

}

}

注意"<whitespace>d"那里。

另一个相关问题是,我希望至少所有以开头的城市都"R"将通过以下查询返回:

  {  

"query":{

"multi_match":{

"query":"R",

"analyzer":"standard",

"fields":[

"city"

]

}

}

}

我期望"Rome",等等…(这是索引中存在的文档),但是,我只能"Rio"再次得到。我希望它的行为类似于SQL LIKE条件,即...

LIKE 'CityName%'

我究竟做错了什么?

回答:

我会这样做:

  • 将令牌生成器更改为edge_nGram您曾说过的需要LIKE 'CityName%'(表示前缀匹配):

      "tokenizer": {

"autocomplete_edge": {

"type": "edge_nGram",

"min_gram": 1,

"max_gram": 100

}

}

  • 将字段指定autocomplete_searchsearch_analyzer。我认为拥有keywordand 是一个不错的选择lowercase

      "mappings": {

"listing": {

"properties": {

"city": {

"type": "string",

"index_analyzer": "autocomplete_term",

"search_analyzer": "autocomplete_search"

}

}

}

}

  • 查询本身很简单:

    {

"query": {

"multi_match": {

"query": "R",

"fields": [

"city"

]

}

}

}

详细的解释是这样的:将城市名称分割为ngram。例如,Rio de Janeiro您将为以下内容编制索引:

               "city": [

"r",

"ri",

"rio",

"rio ",

"rio d",

"rio de",

"rio de ",

"rio de j",

"rio de ja",

"rio de jan",

"rio de jane",

"rio de janei",

"rio de janeir",

"rio de janeiro"

]

您会注意到所有内容都是小写的。现在,您希望查询采用任何文本(是否为小写),并将其与索引中的内容匹配。因此,R应该与上面的列表匹配。

为此,您希望输入文本小写并与用户设置的文本保持一致,这意味着不应对其进行分析。你为什么要这个?因为您已经用ngram分割了城市名称,并且不想为输入文本使用相同的名称。如果用户输入“

RI”,Elasticsearch将小写ri--并将其与索引中的内容完全匹配。

可能更快的替代方法multi_match是使用term,但这要求您的应用程序/网站将文本小写。这样做的原因是term根本不分析输入文本。

    {

"query": {

"filtered": {

"filter": {

"term": {

"city": {

"value": "ri"

}

}

}

}

}

}

以上是 使用ElasticSearch模拟SQL LIKE搜索 的全部内容, 来源链接: utcz.com/qa/422393.html

回到顶部