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的文档。宗旨就是以上两条。