在ElasticSearch6.8中,模糊搜索(比如mysql中的“%aaa%”)的最佳实践是什么

gorkyyrv  于 2021-06-14  发布在  ElasticSearch
关注(0)|答案(1)|浏览(550)

背景:我使用mysql,有数百万的数据,每行有20列,我们有一些复杂的搜索和一些列使用模糊匹配,如 username like '%aaa%' ,除非删除第一个索引,否则不能使用mysql索引 % ,但是我们需要模糊匹配来做搜索,比如satckoverflow搜索,我也检查了mysql fulltext index ,但如果使用其他索引,则不支持在一个sql中进行复杂搜索。
我的解决方案是:添加elasticsearch作为我们的搜索引擎,将数据插入mysql和es,只在elasticsearch中搜索数据
我查过elasticsearch模糊搜索, wildcard 有效,但许多人不建议使用 * 在词的开头,它会使搜索非常慢。
例如:username:'john\u snow' wildcard 工作,但可能很慢

GET /user/_search
{
  "query": {
    "wildcard": {
      "username": "*hn*"
    }
  }
}
``` `match_phrase` 不起作用似乎只对“john snow”这样的标记词起作用

{
"query": {
"match_phrase":{
"dbName": "hn"
}
}
}

我的问题:有没有更好的解决方案来执行包含模糊匹配的复杂查询,如“%no%”或“%hn\u sn%”。
50pmv0ei

50pmv0ei1#

您可以使用ngram标记器,当遇到指定字符列表中的一个字符时,它首先将文本分解为单词,然后发出指定长度的每个单词的n-gram。
添加索引数据、Map、搜索查询和结果的工作示例。
索引Map:

{
    "settings": {
        "analysis": {
            "analyzer": {
                "my_analyzer": {
                    "tokenizer": "my_tokenizer"
                }
            },
            "tokenizer": {
                "my_tokenizer": {
                    "type": "ngram",
                    "min_gram": 2,
                    "max_gram": 10,
                    "token_chars": [
                        "letter",
                        "digit"
                    ]
                }
            }
        },
        "max_ngram_diff": 50
    },
    "mappings": {
        "properties": {
            "title": {
                "type": "text",
                "analyzer": "my_analyzer",
                "search_analyzer": "standard"
            }
        }
    }
}

分析api

POST/ _analyze

{
  "analyzer": "my_analyzer",
  "text": "John_Snow"
}

代币包括:

{
    "tokens": [
        {
            "token": "Jo",
            "start_offset": 0,
            "end_offset": 2,
            "type": "word",
            "position": 0
        },
        {
            "token": "Joh",
            "start_offset": 0,
            "end_offset": 3,
            "type": "word",
            "position": 1
        },
        {
            "token": "John",
            "start_offset": 0,
            "end_offset": 4,
            "type": "word",
            "position": 2
        },
        {
            "token": "oh",
            "start_offset": 1,
            "end_offset": 3,
            "type": "word",
            "position": 3
        },
        {
            "token": "ohn",
            "start_offset": 1,
            "end_offset": 4,
            "type": "word",
            "position": 4
        },
        {
            "token": "hn",
            "start_offset": 2,
            "end_offset": 4,
            "type": "word",
            "position": 5
        },
        {
            "token": "Sn",
            "start_offset": 5,
            "end_offset": 7,
            "type": "word",
            "position": 6
        },
        {
            "token": "Sno",
            "start_offset": 5,
            "end_offset": 8,
            "type": "word",
            "position": 7
        },
        {
            "token": "Snow",
            "start_offset": 5,
            "end_offset": 9,
            "type": "word",
            "position": 8
        },
        {
            "token": "no",
            "start_offset": 6,
            "end_offset": 8,
            "type": "word",
            "position": 9
        },
        {
            "token": "now",
            "start_offset": 6,
            "end_offset": 9,
            "type": "word",
            "position": 10
        },
        {
            "token": "ow",
            "start_offset": 7,
            "end_offset": 9,
            "type": "word",
            "position": 11
        }
    ]
}

索引数据:

{
  "title":"John_Snow"
}

搜索查询:

{
    "query": {
        "match" : {
            "title" : "hn"
        }
    }
}

搜索结果:

"hits": [
            {
                "_index": "test",
                "_type": "_doc",
                "_id": "1",
                "_score": 0.2876821,
                "_source": {
                    "title": "John_Snow"
                }
            }
        ]

如果你想做一个自动完成的搜索,请参考这个博客。
另一个搜索查询

{
    "query": {
        "match" : {
            "title" : "ohr"
        }
    }
}

上面的搜索查询没有显示结果

相关问题