php es 短语精确搜索,Elasticsearch:在搜索引擎中如何实现完全匹配(内容精确匹配)查询...

本文地址:

在有搜索引擎之前,我们查文档常使用顺序匹配。比如要搜索 "我的祖国是花园",需要在文档中顺序扫描,找到完全匹配的子句。

在有了搜索引擎后,我们对查询语句做的处理就不一样了。我们通常会先分词,然后查找对应的词条索引,最后得到评分由高到低的文档列表。我一度以为没法实现完全匹配了,直到一个硬需求的出现。花了一天时间,把完全匹配用搜索引擎的思维整理出来。

简要描述实现思路,字段按一字一词的形式分词,再利用短语查询来搜索。

ES中,可以实现一字一词的的分词器是NGram。

Ngram分词的官方文档地址: https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-ngram-tokenizer.html

它其实是一个上下文相连续字符的分词工具,可以看官方文档中的例子。当我们将它 min_gram 和 max_gram 都设为1时,它会按一字一词的形式分词。比如“shinyke@189.cn”,分词的结果是["s" , "h" , "i" , "n" , "y" , "k" , "e" , "@" , "1" , "8" , "9" , "." , "c" , "n" ]。

/index_name/

{

"settings": {

"analysis": {

"analyzer": {

"charSplit": {

"type": "custom",

"tokenizer": "ngram_tokenizer"

}

},

"tokenizer": {

"ngram_tokenizer": {

"type": "nGram",

"min_gram": "1",

"max_gram": "1",

"token_chars": [

"letter",

"digit",

"punctuation"

]

}

}

}

}

}

以上语句中,构建了一个

名为“charSplit”的分析器。它使用一个名为“ngram_tokenizer”的Ngram分词器。

可以用如下语句测试charSplit分析器,可以看到一字一词的效果:

curl -POST http://IP:port/{index_name}/_analyze?pretty&analyzer=charSplit

"测试语句"

把这个分析器在mapping里用起来:

...

"sender": {

"type": "string",

"store": "yes",

"analyzer": "charSplit",

"fields": {

"raw": {

"type": "string",

"index": "not_analyzed"

}

},

...

接下来就可以用match_phrase来实现完全匹配查询。

/{index_name}/{type_name}/_search

{

"query": {

"multi_match": {

"query": "@189.cn",

"type": "phrase", //type指定为phrase

"slop": 0, //slop指定每个相邻词之间允许相隔多远。此处设置为0,以实现完全匹配。

"fields": [

"sender"

],

"analyzer": "charSplit", //分析器指定为charSplit

"max_expansions": 1

}

},

"highlight": { //测试高亮是否正常

"pre_tags": [

""

],

"post_tags": [

""

],

"fragment_size": 100,

"number_of_fragments": 2,

"require_field_match": true,

"fields": {

"sender": {}

}

}

}phrase查询原始的作用是用来做短语查询,

它有一个重要的特点:有顺序。我们利用了它匹配的有序性,限制slop为0,则可实现完全匹配查询。

以上语句返回的结果是:

{

"took": 18,

"timed_out": false,

"_shards": {

"total": 9,

"successful": 9,

"failed": 0

},

"hits": {

"total": 1,

"max_score": 0.40239456,

"hits": [

{

"_index": "index_name",

"_type": "type_name",

"_id": "AU9OLIGOZN4dLecgyoKp",

"_score": 0.40239456,

"_source": {

"sender": "18977314000 <18977314000@189.cn>, 李X <18977314000@189.cn>, 秦X <18977314000@189.cn>, 刘X <18977314000@189.cn>"

},

"highlight": {

"sender": [

"18977314000 <18977314000@189.cn>, 李X <18977314000@189.cn>, 秦纯X <18977314000@189.cn>, 刘X <189773140"

]

}

}

]

}

}

到此,就实现了完全匹配查询。实际环境中用NGram做一字一词分析器的时候会更细致一些,比如有一些字符需要用stop word过滤掉。这些细节可以根据实际需要在构造分析器时添加filter实现,在此不做赘述。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值