elasticsearch---search in depth之Proximity matching

match query能告诉我们doc中是否含有我们要找的word,但是无法告诉我们这些word之间的关联,比如说距离。

words之间的关联关系不是通过引进一种新的查询类型就可以解决的,但是words之间的一些相关性,比如临近word对我们还用的。如果两个word相邻,应该比两个word之间相隔几个word甚至几个段落相关性更强。这就是phrase matching / proximity matching所做的事情。

1:phrase match

phrase match意在找出word之间的临近关系。这是基于lucene索引中存储的term在doc中出现的position信息来判断的。

因此phrase match属于position-aware类型的query。会匹配到跟query string生成的word list中各个word相对位置一致的doc。

tip:phase match的底层实现是span query。span query一般不常用,一些特殊格式的query才会用到,比如专利号。

严格按照word的相对位置匹配可能过于严格,因此es提供了slot参数,来控制这个偏差。在slot范围内,偏差越小,score越高,显而易见。

slot的意义是:需要移动一个term多少次才能使得query跟doc完全match到。

两种情况:一是缺失某些term,二是term一致,但是顺序不一致。都需要slot来控制。

不再举例赘述。注意的是两个term交换位置,slot=2.

那这种匹配对于muiti_value类型是否会有异常呢?

name: ["John Smith" ,"Harword Jack"].

如果query string = "Smith Harword" 结果会是什么?很不幸,可以match到。这是由lucene的对multi-value类型在index中的存储决定的。

其位置信息是:position1=John position2=Smith position3=Harword。lucene把multi-value当成了一个大的value。因此,不言而喻。

但是这并不是我们想要查询到的结果!幸好,es提供了一个妥协的解决方式,position_offset_gap。

指定这个参数来确定multi-value之间的的距离,比如position_offset_gap=1000,则位置信息如下:

position1=John position2=Smith position1003=Harword

因此就不会匹配到了,当然slop制定为1000是可以匹配到的。所以觉得是一种妥协的解决方法。

2:proximity matching for relevance

我们可以用一个简单的match query作为一个must clause,同时用minimun_should_match参数控制,这样可以去除长尾,然后用phrase match query作为一个should clause。must clause 和 should clause 共同组成一个bool。这样能should clause match到的doc可以得到较高的分数。可以起到control precision的目的。

3:improving performance

phrase query 和 proximity query( with slop )性能要比简单的term query差,因为term query不需要考虑位置信息。

lucene给出了测试数据大概有20倍。其实远没有这么吓人。如何减少这种性能损耗呢?尽量减少phrase query需要匹配的doc数目。

其实,用户关心的也就是前边几页的搜索结果。普通的match query会对所有match的doc进行score。这也是一项费时的操作。因此我们可以在match到的记录中从每一个shard中选取top的几条记录,进行score。组成最终的result。这样就省去了过多需要match的doc。

es提供了rescore和window_size参数控制每个shard返回的记录条数。因此整个流程应该是:

一个match query,用minimun_should_match控制匹配的记录,然后制定rescore query(内部嵌套一个match_phrase query),配合window_size参数,只对每个shard的top window_size个doc进行score操作。

4:find associated word

抛出了一个问题:phrase query的查询必须是要匹配到word的,并不关心word的顺序。而这种顺序关系是有差别的。

doc1:Sue ate the alligator。

doc2:The alligator ate sue。

当我们查询 “the hungry alligator ate sue”的时候,doc1跟doc2的得分是相同的,匹配到了同样多的word。但是doc2理应该得到更高的分数。怎么解决这种问题?

index过程中我们是对每一个term进行的analyzed,进一步我们可以把相邻的term做成一个term,每两个一组,每三个一组,以此类推。运用multi_field,制定不同的analyzer(type=shingles 配合min_shingles_size max_shingles_size output_unigrams字段,来决定分词的大小,以及是否输出单个term的分词,因为采用了multifield,所以不需要输出单个term的分词,在主字段中存储的就是单个term的分词),query的时候以单个term的field进行match query,然后用多个term的field来增加相关性。类似以下查询结构:

“query” : {

    "bool" : {

          "must" : { "match" : { "title" : "the hungry alligator ate sue"} },

          "should" : { "match" : {"title.shingles" : "the hungry alligator ate sue"}}

    }

}

should clause来增加相关性。shingles是mutifield的,index过程中,相邻的两个word作为一个term,比如 "sue ate", "ate the", "the alligator"。

一般指定size为2就差不多能满足要求了。这种做法会增加term的数量,index也会增大,但是跟match phrase相比,这样更加灵活,同时性能也会好一些。细细想想,我们并没有在查询的时候考虑position信息,而是把这种信息放到了index过程中,因此查询时候只是match query,性能更佳。




 





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值