elasticsearch---search in depth之struct search

来源:互联网 发布:淘宝中药材会假吗 编辑:程序博客网 时间:2024/05/18 17:00

struct search,顾名思义,针对结构化数据进行的搜索。数字,日期等都是结构化的数据,文本当然也可以,可以联想一下编程语言中的enum类型,struct等。

可以在这些结构化数据上进行一些逻辑运算,比如compare。关于这部分数据的搜索没有similar的概念,要么是是,要么是非,因此doc之间的相关性不在考虑之列,这样做有其逻辑合理性。

1:精确匹配

这里not_analyzed作用凸显了。

不赘述数字类型的情况了,很容易理解,匹配一个数字的情况。

对于Text类型,analyzed跟not_analyzed的结果是不一样的。在精确匹配的前提下,field要设置成not_analyzed。

一个简单例子:index中存储的是 hello world, 是analyzed。如果用termquery,term=hello,是可以匹配到的,但是如果term设置为hello world,则匹配不到结果。

因为termquery是not_analyzed,把hello world当作了一个term,而索引中则是两个不同的term,所以无法得到想要的结果。

回到我们的议题,我们要的就是精确匹配,所以index设置成not_analyzed就可以了。

说一下下filter的internal operation:

(1)查找匹配的doc

(2)根据匹配结果构建一个bitset

(3)cache这个bitset,复用。

如果执行一个filtered 的query,则filter执行在先,query执行在后,这样到query执行的时候有些doc就已经过滤掉了,可以提升效率。

2:联合filter

跟sql类比,用boolfilter。should===or  must===and  must_not===not。

多个boolfilter可以嵌套实现复杂的查询。

3:多值匹配

类比1中是精确匹配,完全一致的,是一种equal的关系,所有设置了not_analyzed,因此只能匹配一个term。而存在很多情况是要匹配多个值的,而且对于没一个值都必须是精确的,比如输入地址:shandong liaoning等。匹配到哪一个term都可以。但没一个都是精准的。这种情况下就采用了terms-query。而且不能设置not_analyzed属性。

由此可见,无论是term-query还是terms-query都是一种contain的关系,而非equal。一个doc里边只要含有对应的term就可以,不需要完全一样。

对于inverted-index来说,如果要实现完全一致,代价是很高的(not_analyzed除外)。因为你首先要匹配到一个doc,然后再去查询整个index来一一确认是否还有term的列表中存在这个doc的id,这是代价很大的操作。

但是也给我们提供了一种处理这种问题的思路:我们在indexing过程中,记录一下每一个doc含有的term个数,作为index的一个字段,这样我们匹配的时候,只需要check这个term-num就可以了。

4:区间查询

rang-query,查询符合一个区间的记录。比如数字区间,时间区间等,也支持string类型的区间。

对数字,时间的range查询是比较高效的。而对string类型则需要格外注意,range操作需要一个termfilter去匹配所有落在range中term,相比data和number,这个代价要高的多。

5:null的处理

“”, [], null, [null]都是空值,index中是不会存储的,因此以上值对es来说都是等价的。但现实中确实有些字段存在空值,我们如何去判断呢?有类似有sql中的is null语句么?

两个fileter可以处理:exist-filter和null-filter。

exist-filter:只要对应字段有值,该doc就会match。

null-filter:null值则match,包括这个字段不存在也是null。

这种判定同样适合于notflated的类型,比如name:{"first" : "james", "last" : "blunt"}。这种结构其实都是扁平话存储的。类似与name.first和name.last俩字段。

因此可以单独判定name.first和name.last,也可以直接判定name.。对name的判定则翻译成对name.first和name.last的判定,只需要一个boolquery即可。

现实字段中的空值有些时候我们是要保存的,但是在es中确不存储,如何搞?弄一个站位符吧。不过这个占位符要跟field的类型匹配,同时还不要跟正常值冲突。

6:cacheing

1中所说,filter构建的bitset是cache的关键,这个bitset可以被重用,来提升效率。这个bitset是足够聪明的,可以动态更新,每当加入新的记录,都会自动update。因此不用担心过期问题。

多数leaf-filter是cache的,比如term-filter,而compound-filter则不cache。

leaf-filter直接操作inverted-index,而compound-filter直接利用leaf-filter的结构即可,速度也很可观,因此无需cache。

有一些filter不cache是有意义的。

基于时间的filter:因为支持比如now这样的功能,随时可变,因此无需cache。

基于geo的filter:每一个user需要的geo信息各异,cache也无意义。

script-filter:script对于es是不透明的,cache没意思。

最后,是否cache要根据业务需求,如果上述不cache的确实需要cache,修改_cache属性即可,很灵活。

7:filter的顺序

原则就是尽量能提前排除掉更多的doc,并却保证快的查询速度。因此

第一:过滤能力强的filter需要前置

第二:cache的filte需要前置。

有一个经典的关于时间的例子可以参考es的文档。宗旨就是以上两条。


0 0