2019独角兽企业重金招聘Python工程师标准>>>
记录一下最近用到的es查询,感觉常见的应该都遇上了,下午抽空更新。
又拖,一直拖,终于闲下来了,现在开始写吧。。。
es作为一款基于文档的非关系型数据库,elasticsearch,既然带有search,所以,可以猜到他的检索能力是非常出色的,今天,我想记录一下我最近用的es的查询分析功能,先说基本查询,然后模糊查询,最后说聚合查询吧。
一,简单查询
1,先看一下java api
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index); RangeQueryBuilder rangequerybuilder = QueryBuilders .rangeQuery("date") .from(startTime).to(endTime); TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(key, value); TermQueryBuilder termQueryBuilderNot = QueryBuilders.termQuery("status", "0"); searchRequestBuilder = searchRequestBuilder.setQuery(QueryBuilders.boolQuery().must(rangequerybuilder).must(termQueryBuilder).mustNot(termQueryBuilderNot)) .setFrom(0).setSize(10); SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
上面是java查询es最基本的api。
client.prepareSearch(index);指定index,提示:es6中每个index只能有一个type,所以查询时type存在的意义不大,且es支持查询时不带type
RangeQueryBuilder rangequerybuilder 可以限定范围
TermQueryBuilder termQueryBuilder 可以查询等于某值的结果,拼装searchRequestBuilder时,配合.mustNot(),must()使用
searchRequestBuilder用于最后拼装上面的查询限定条件
.setFrom(0).setSize(0)代表从查询结果的第0个开始显示,共显示10个
.execute().actionGet();这个是真正的向es集群发送请求的语句
了解了基本的查询之后,我们在说一下模糊查询
二,模糊查询
我用到的是正则匹配,比如实际值是https://my.oschina.net/u/3796880/blog/write/3042734,但你想通过https://my.oschina.net/u/3796880/blog/write就可以查出来,后面的值模糊匹配,ok,开始
WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery(key, value);
key是es中的字段名,value是“https://my.oschina.net/u/3796880/blog/write*”,道理懂吧。值“*oschina.net/u/3796880/blog*”也可以查询来,总之就是正则嘛
同理前缀查询道理也一样
PrefixQueryBuilder prefixQueryBuilder=QueryBuilders.prefixQuery(key,value)
我暂时没用,想用的同学可自行了解一下
说道这里,我想到自己踩过的一个坑
TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery(key, values);
TermsQueryBuilder 支持查询某字段的多个值,比如查询语言是java,c,c++的数据,可以这么写
String values[]={"java","c","python"}; TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("language", values);
是不是很方便?但是,有一天,需求变了,language字段不是精准查询,要改为模糊匹配。第一反应是so eazy,把wildcardQuery改为wildcardsQuery不得了,但。。。最后发现es没提供这个方法。。。,最后只能一个一个加了
但怎么加呢,他们之间是或的关系,理所当然这样写
WildcardQueryBuilder wildcardQueryBuilder1 = QueryBuilders.wildcardQuery(key, value1); WildcardQueryBuilder wildcardQueryBuilder2 = QueryBuilders.wildcardQuery(key, value2); WildcardQueryBuilder wildcardQueryBuilder3 = QueryBuilders.wildcardQuery(key, value3);
最后
QueryBuilders.boolQuery().must(其他QueryBuilders).should(wildcardQueryBuilder1).should(wildcardQueryBuilder2).should(wildcardQueryBuilder3)
但,最后发现查不到数据,最后解决办法:需要外面包一层must
BoolQueryBuilder queryBuilder= QueryBuilders.boolQuery().should(wildcardQueryBuilder1).should(wildcardQueryBuilder2).should(wildcardQueryBuilder3); QueryBuilders.boolQuery().must(其他QueryBuilders).must(queryBuilder);
完美解决!
三、聚合查询
1、某字段聚合
最常见的需求,查询某字段分组后的个数,比如男生几个,女生几个,类似于sql中的group by
AggregationBuilder aggregationBuilder = AggregationBuilders.terms("sex").field("sex).size(1000);
第一个“sex”代表你给聚合完的数据起的名字
第二个“sex”,即.field("sex)代表真实的es中存在的,你想要分组的字段名
1000,代表本次查询支持最大的buckets数量,此例中,不出意外,最大是3,非男即女或空。所以此处的1000改为3也无所谓。即有几个分组就会有几个buckets。
2、简单运算
计算平均值 AggregationBuilders.avg(自己取的名字).field(实际字段名)
计算某字段的50线,60线...95线,99线 AggregationBuilders.percentiles(自己取的名字).field(实际字段名).percentiles(50.0, 60.0, 70.0, 80.0, 90.0, 95.0, 99.0);
将某字段的值按大小分组 如,统计工资在0-100,100-150,150-200,大于200的个数 RangeAggregationBuilder rangeQueryBuilder2 = AggregationBuilders.range("tolerating").addRange(0, 10000).field("load.duration"); RangeAggregationBuilder rangeQueryBuilder1 = AggregationBuilders.range("least").addRange(0, 100).field("wages"); RangeAggregationBuilder rangeQueryBuilder2 = AggregationBuilders.range("less").addRange(100, 150).field("wages"); RangeAggregationBuilder rangeQueryBuilder3 = AggregationBuilders.range("many").addRange(150, 200).field("wages"); RangeAggregationBuilder rangeQueryBuilder4 = AggregationBuilders.range("mush").addRange(200, 10000000000).field("wages"); 然后再searchRequestBuilder中加入聚合 SearchResponse searchResponse = searchRequestBuilder.addAggregation(rangeQueryBuilder1) .addAggregation(rangeQueryBuilder2) .addAggregation(rangeQueryBuilder3) .addAggregation(rangeQueryBuilder4) 这里有个不方便的地方,比如大于200的,这个不好限制,写成【200,1000000000】确实结果大概率是对的,但加入真的有一个人,工资超级高,那你就把它,它,哈哈,落下了。怎么办呢? 大于200:RangeAggregationBuilder rangeQueryBuilder1 = AggregationBuilders.range("must").addUnboundedFrom("200").field("wages"); 小于100:RangeAggregationBuilder rangeQueryBuilder1 = AggregationBuilders.range("must").addUnboundedTo("100").field("wages");
时间分组 方法1: AggregationBuilders.dateHistogram(自己取的名字).field(实际字段名).dateHistogramInterval(DateHistogramInterval.SECOND);表示按秒分组 还有DateHistogramInterval.MINUTE,DateHistogramInterval.HOURDate,HistogramInterval.DAY 方法2: AggregationBuilders.dateHistogram(自己取的名字).field(实际字段名).interval(毫秒值);
3、多重聚合
AggregationBuilder firstAggregationBuilder = AggregationBuilders.terms(agg1).field(agg1).size(1000); AvgAggregationBuilder secondAggregationBuilder = AggregationBuilders.avg(agg2).field(agg2); firstAggregationBuilder.subAggregation(secondAggregationBuilder) 最后searchRequestBuilder.addAggregation(firstAggregationBuilder)即可
四、哈哈哈
1,有不对或不懂的地方,私信我,或者评论区评论都可以
2,有实现不了的查询需求,发出来,大家一起想想,哦了