首页 > 代码库 > Elasticsearch 检索

Elasticsearch 检索

说到查询,那么索引也是一个绕不开的话题,可以说,没有索引就没有检索,先来看一个示意图

技术分享

 

左边是索引过程,右边是检索过程。关键的步骤是分词过程,我用等号表示这两个过程一样,而且,必须一样,这个等号并不是模糊的流程的相同,而且必须是逻辑也相同。 简单来讲,采用的分词器和分词流程需要一样,否则,很有可能填进去的文档,搜不出来。

 

本篇重点在如何用JAVA API实现查询上,就不深入说索引的过程了,以后有时间再深入。

 

对于查询,有两个基础的类型,Match查询,和Term查询。这也是跟索引过程相关的。刚开始接触的索引,我就想,如果把所有的内容都做搜索,那么一是需要建立非常多的索引,再一个是要保存特别多的原始数据,随着了解的加深,我发现并不是这样的。

 

在进行索引的时候,先新建文档,在往文档中添加字段时,有Index设置和Store设置。index设置就是是否要对这个字段用分词器进行分词。举个例子,有个字段A,内容为中华人民共和国国歌,以中文分词器IK为例,如果不进行分词,那么往索引中插入的时候,直接用一个词“中华人民共和国国歌”。如果A字段设置为进行索引,那么IK分词器就会将“中华人民共和国国歌”分解为“中华人民共和国”和“国歌”两个词,往索引中添加的时候,是两个记录。

对于Store选项,如果选择Yes,就是存储这个字段的原始值,对于字段A来说,就是保存“中华人民共和国国歌”,这样,在检索之后,如果查询到字段A,可以返回A的原始值。如果选择Store为No,并且设置为A进行索引,那么A字段的原始值就不可知了。索引中只存在“中华人民共和国”和“国歌”,并不存在“中华人民共和国国歌”。你可以检索到字段A,但是A的原始值是什么,ES就不知道了,需要去原始的数据源中找出来。

 

这两个设置是十分关键的,比如id,基本不需要进行索引分词,直接存储就是了,而且,你查询的时候,也肯定不需要对id进行分词,所以,这个就是term查询的用处。term就是词的意思,Lucene中将分词之后的结果成为Term,所以,像id这样的不需要分词的,直接就跟经过分词步骤的词一样了,可以用这个词直接去倒排索引中查询了。所以,Term查看的字段,最好设置为Index为No,否则,一般搜不到。

 

Store选项可以有效减小ES的存储规模,你想想,你用百度去搜索,肯定都会到目标的网页,而不是在百度里面浏览,百度只要告诉你,你想去的网页的URL就可以了。所以,在进行索引的时候,像整个网页的内容,并不是需要的,需要的是对整个网页进行分词之后产生的词,然后就可以将原始的网页文本丢弃了。当然,百度也存储了这个内容的,百度快照就是。

 

Match查询就是需要对搜索的关键词进行分词,然后将分词的结果拿到倒排索引里面去检索,检索之后,再对这个结果进行相关性分词,然后排序进行输出。可以看出,Match查询要比Term查询多了至少两步,分词和相关性计算。

 

比如说我们要索引一个网页,网页有一些基本meta信息。那么首先,我们把网页给抓取到,分析网页里面的内容。网页的meta信息比较关键,我们提取出来,准备构建一个文档,网页的关键字,meta信息,更新时间等这些都可以成为

 

除了这两类最主要的,还有范围查询,bool查询等,这些都是跟SQL一样的组合查询。

SearchRequestBuilder是最主要的查询方法,QueryBuilders提供了多种构造查询语句的方式。Kibana里面集成的DevTools是使用Query DSL非常方便的一个工具。

技术分享

 

SearchRequestBuilder searchRequestBuilder = client.prepareSearch((String[])tempIndices.toArray(new String[tempIndices.size()]));

searchRequestBuilder.setTypes(typesName);

searchRequestBuilder.setQuery(qb);

searchRequestBuilder.addStoredField(field);//设置返回的字段,注意,这里返回的必须是Stored是Yes的。

searchRequestBuilder.setSize(size);

searchRequestBuilder.setFrom(from);

SearchResponse searchResponse = requestBuilder.execute().actionGet();

 

那么如何构造Query?这就是如何从我们的查询转化成ES的Query DSL,有关kibana使用的就是DSL,有关DSL的介绍,查看elastic.co或者网站翻译的Elasticsearch权威指南。尽量还是参考elastic.co的,因为ES更新比较快,最靠谱的还是上面的介绍。

 

QueryBuilders.rangeQuery();//范围查询

 

QueryBuilders.geoDistanceRangeQuery("fieldName", new GeoPoint(Long.parseLong("经度"), Long.parseLong("纬度")))

.from( "1km")

.to("2km")

.includeLower(true)

.includeUpper(true);//地理位置插叙

 

QueryBuilders.termQuery("field", "keyword");//term查看

 

QueryBuilders.matchQuery("field", "keyword");//match查看

 

另外,可以使用QueryBuilders.boolQuery();将上面的query联合起来,连接的关系有Must(等同于SQL的AND),MustNot(等同于SQL的NOT),SHOULD(等同于OR)

 

基本上,以上都是初步的查询API。

Elasticsearch 检索