ElasticSearch 关于查询
1. 查询
term查询
term 查询是代表完全匹配,搜索之前不会对你搜索的关键字进行分词,直接拿 关键字 去文档分词库中匹配内容
查询语句:
POST /sms-logs-index/sms-logs-type/_search { "from": 0, # 类似limit,指定查询第一页 "size": 5, # 指定一页查询几条 "query": { "term": { "province": { "value": "北京" } } } }
查询结果:
{ "took" : 0, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 3, "max_score" : 1.3862944, "hits" : [ { "_index" : "sms-logs-index", "_type" : "sms-logs-type", "_id" : "9", "_score" : 1.3862944, "_source" : { "createDate" : "2021-03-25", "sendDate" : "2021-03-25", "longCode" : "12347000911", "mobile" : "1506890005", "corpName" : "中国李宁", "smsContent" : "【中国李宁】尊敬的客户,您充值的话费100元,现已经成功到账,您的当前余额为125元,2020年12月18日14:35", "start" : 0, "operatorId" : 1, "province" : "北京", "ipAddr" : "10.126.2.6", "replyTotal" : 11, "fee" : 14 } }, { "_index" : "sms-logs-index", "_type" : "sms-logs-type", "_id" : "4", "_score" : 0.9808292, "_source" : { "createDate" : "2021-03-25", "sendDate" : "2021-03-25", "longCode" : "20697000911", "mobile" : "1586890005", "corpName" : "中国移动", "smsContent" : "【中国移动】尊敬的客户,您充值的话费100元,现已经成功到账,您的当前余额为125元,2020年12月18日14:35", "start" : 0, "operatorId" : 1, "province" : "北京", "ipAddr" : "10.126.2.6", "replyTotal" : 11, "fee" : 4 } }, { "_index" : "sms-logs-index", "_type" : "sms-logs-type", "_id" : "11", "_score" : 0.6931472, "_source" : { "createDate" : "2021-03-25", "sendDate" : "2021-03-25", "longCode" : "11117000911", "mobile" : "1581230005", "corpName" : "淮安易懂", "smsContent" : "【淮安易懂】尊敬的客户,您充值的话费100元,现已经成功到账,您的当前余额为125元,2020年12月18日14:35", "start" : 0, "operatorId" : 1, "province" : "北京", "ipAddr" : "10.126.2.6", "replyTotal" : 11, "fee" : 41 } } ] } }
java代码实现方式:
RestHighLevelClient client = ESClient.getClient(); String index="sms-logs-index"; String type="sms-logs-type"; ObjectMapper objectMapper=new ObjectMapper(); @Test public void termQuery() throws Exception{ //1.创建request对象 SearchRequest searchRequest = new SearchRequest(index); searchRequest.types(type); //2.指定查询条件 SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder(); searchSourceBuilder.from(0); searchSourceBuilder.size(5); searchSourceBuilder.query(QueryBuilders.termQuery("province","北京")); searchRequest.source(searchSourceBuilder); //3.执行查询 SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT); //4.获取到 _source中的数据并展示 for(SearchHit hit:search.getHits().getHits()){ Map<String, Object> sourceAsMap = hit.getSourceAsMap(); System.out.println(sourceAsMap); } }
运行结果:
{province=北京, sendDate=2021-03-25, fee=14, mobile=1506890005, smsContent=【中国李宁】尊敬的客户,您充值的话费100元,现已经成功到账,您的当前余额为125元,2020年12月18日14:35, ......}
{province=北京, sendDate=2021-03-25, fee=4, mobile=1586890005, smsContent=【中国移动】尊敬的客户,您充值的话费100元,现已经成功到账,您的当前余额为125元,2020年12月18日14:35,......}
{province=北京, sendDate=2021-03-25, fee=41, mobile=1581230005, smsContent=【淮安易懂】尊敬的客户,您充值的话费100元,现已经成功到账,您的当前余额为125元,2020年12月18日14..........}
1.1 terms查询
terms 和 term 查询的机制一样,搜索之前不会对你搜索的关键字进行分词,直接拿 关键字 去文档分词库中匹配内容 terms:是针对一个字段包含多个值 term : where province =北京 terms: where province = 北京 or province =? (类似于mysql 中的 in) 也可针对 text, 只是在分词库中查询的时候不会进行分词
查询语句:
POST /sms-logs-index/sms-logs-type/_search { "from":0, "size":5, "query": { "terms":{ "province": [ "北京", "武汉" ] } } }
java代码实现方式:
public void termsQuery() throws Exception{ //1.创建request对象 SearchRequest searchRequest = new SearchRequest(index); searchRequest.types(type); //2.指定查询条件 SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder(); searchSourceBuilder.from(0); searchSourceBuilder.size(5); searchSourceBuilder.query(QueryBuilders.termsQuery("province","北京","武汉")); searchRequest.source(searchSourceBuilder); //3.执行查询 SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT); //4.获取到 _source中的数据并展示 for(SearchHit hit:search.getHits().getHits()){ Map<String, Object> sourceAsMap = hit.getSourceAsMap(); System.out.println(sourceAsMap); } }
1.2 match查询
match 查询属于高级查询,会根据你查询字段的类型不一样,采用不同的查询方式 查询的是日期或者数值,他会将你基于字符串的查询内容转换为日期或数值对待 如果查询的内容是一个不能被分词的内容(keyword),match 不会将你指定的关键字进行分词 如果查询的内容是一个可以被分词的内容(text),match 查询会将你指定的内容根据一定的方式进行分词,去分词库中匹配指定的内容 match 查询,实际底层就是多个term 查询,将多个term查询的结果给你封装到一起
1.2.1 match_all 查询
查询全部内容,不指定查询条件
查询语句:
POST /sms-logs-index/sms-logs-type/_search { "query": { "match_all": { } } }
java 代码实现方式:
public void matchAllSearch() throws IOException { // 1.创建request对象 SearchRequest request = new SearchRequest(index); request.types(type); // 2.创建查询条件 SearchSourceBuilder builder = new SearchSourceBuilder(); builder.query(QueryBuilders.matchAllQuery()); // ES 默认只查询10条数据 builder.size(20); request.source(builder); // 3.执行查询 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 4.输出查询结果 for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getSourceAsMap()); } System.out.println(response.getHits().getHits().length); }
1.2.2 mach查询
指定一个field 作为查询条件
match查询会针对不同的类型执行不同的策略
- 查询text类型的数据会对条件进行分词
查询语句:
POST /sms-logs-index/sms-logs-type/_search { "query": { "match": { "smsContent": "收货安装" } } }
java代码实现方式:
public void matchQuery() throws IOException { // request SearchRequest request = new SearchRequest(index); request.types(type); // 查询条件 SearchSourceBuilder builder = new SearchSourceBuilder(); builder.query(QueryBuilders.matchQuery("smsContent","收货安装")); request.source(builder); // 执行查询 SearchResponse response = client.search(request,RequestOptions.DEFAULT); // 获取数据 for (SearchHit hit : response.getHits().getHits()) { Map<String, Object> result = hit.getSourceAsMap(); System.out.println(result); } }
1.2.3 布尔match查询
基于一个field 匹配的内容,按照 and 或者or的方式连接
可以查询既包含条件1,又包含条件2的内容,也就是and的效果,也可以实现or的效果
查询语句:
POST /sms-logs-index/sms-logs-type/_search { "query": { "match": { "smsContent": { # 既包含 中国 也包含 健康 "query": "中国 健康", "operator": "and" } } } } #布尔match查询 POST /sms-logs-index/sms-logs-type/_search { "query": { "match": { "smsContent": { "query": "中国 健康", "operator": "or" } } } }
java代码实现方式:
@Test public void booleanMatchQuery() throws IOException { // request SearchRequest request = new SearchRequest(index); request.types(type); // 查询条件 SearchSourceBuilder builder = new SearchSourceBuilder(); // 指定and或者or builder.query(QueryBuilders.matchQuery("smsContent","中国 健康").operator(Operator.AND)); request.source(builder); // 执行查询 SearchResponse response = client.search(request,RequestOptions.DEFAULT); // 获取数据 for (SearchHit hit : response.getHits().getHits()) { Map<String, Object> result = hit.getSourceAsMap(); System.out.println(result); } }
1.2.4 multi_match查询
match 针对一个field 做检索,multi_math 针对多个field 进行检索,多个field对应一个文本。
查询语句:
POST /sms-logs-index/sms-logs-type/_search { "query":{ "multi_match": { "query": "北京", #指定 text "fields": ["province","smsContent"] #指定field } } }
java代码实现方式
public void multiMatchSearch() throws IOException { // 1.创建request对象 SearchRequest request = new SearchRequest(index); request.types(type); // 2.创建查询条件 SearchSourceBuilder builder = new SearchSourceBuilder(); //-------------------------------------------------------------- builder.query(QueryBuilders.multiMatchQuery("北京","province","smsContent")); //-------------------------------------------------------------- request.source(builder); // 3.执行查询 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 4.输出查询结果 for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getSourceAsMap()); } System.out.println(response.getHits().getHits().length); }
2.其他查询
2.1 id查询
#id 查询
GET /sms-logs-index/sms-logs-type/1
java代码实现方式:
public void findById() throws IOException { // 创建GetRequest对象 GetRequest request = new GetRequest(index,type,"1"); // 执行查询 GetResponse response = client.get(request, RequestOptions.DEFAULT); // 输出结果 System.out.println(response.getSourceAsMap()); }
2.1.2 ids查询
根据多个id 查询,类似 mysql 中的 where in (id1,id2...)
查询语句:
#ids 查询 POST /sms-logs-index/sms-logs-type/_search { "query": { "ids": { "values": ["1","2","3"] } } }
java代码实现方式:
public void findByIds() throws IOException { // 创建request对象 SearchRequest request = new SearchRequest(index); request.types(type); // 指定查询条件 SearchSourceBuilder builder = new SearchSourceBuilder(); //-------------------------------------------------- builder.query(QueryBuilders.idsQuery().addIds("1","2","3")); //------------------------------------------------------ request.source(builder); // 执行 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 输出结果 for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getSourceAsMap()); } }
2.2 prefix 查询
前缀查询,可以通过一个关键字去指定一个field 的前缀,从而查询到指定文档
查询语句:
POST /sms-logs-index/sms-logs-type/_search { "query": { "prefix": { "corpName": { "value": "途虎" } } } }
#match 查询 在这里是什么都查不到的 和上边的prefix 做比较
POST /sms-logs-index/sms-logs-type/_search
{
"query": {
"match": {
"corpName": "途虎"
}
}
}
java代码实现方式:
public void findByPrefix() throws IOException { // 创建request对象 SearchRequest request = new SearchRequest(index); request.types(type); // 指定查询条件 SearchSourceBuilder builder = new SearchSourceBuilder(); //-------------------------------------------------- builder.query(QueryBuilders.prefixQuery("corpName","途虎")); //------------------------------------------------------ request.source(builder); // 执行 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 输出结果 for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getSourceAsMap()); } }
2.3 fuzzy查询
模糊查询,我们可以输入一个字符的大概,ES 可以根据输入的大概去匹配内容。查询结果不稳定
查询语句:
#fuzzy 查询 POST /sms-logs-index/sms-logs-type/_search { "query": { "fuzzy": { "corpName": { "value": "东风快滴", #指定前边几个字符是不允许出现错误的 "prefix_length": 3 } } } }
java代码中实现方式:
@Test public void fuzzyQuery() throws IOException { // 依然使用SearchRequest SearchRequest request = new SearchRequest(index); request.types(type); // 查询 SearchSourceBuilder builder = new SearchSourceBuilder(); builder.query(QueryBuilders.fuzzyQuery("corpName","东风快滴")); //builder.query(QueryBuilders.fuzzyQuery("corpName","东风快滴").prefixLength(2)); request.source(builder); // 执行 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 获取结果 for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getSourceAsMap()); } }
2.4 wildcard查询
通配查询,同mysql中的like 是一样的,可以在查询时,在字符串中指定通配符*和占位符?
查询语句:
#wildcard 查询 POST /sms-logs-index/sms-logs-type/_search { "query": { "wildcard": { "corpName": { "value": "中国*" } } } } #wildcard 查询 POST /sms-logs-index/sms-logs-type/_search { "query": { "wildcard": { "corpName": { "value": "中国??" #中国移动 } } } }
java代码实现方式:
public void findByWildCard() throws IOException { // 创建request对象 SearchRequest request = new SearchRequest(index); request.types(type); // 指定查询条件 SearchSourceBuilder builder = new SearchSourceBuilder(); //-------------------------------------------------- builder.query(QueryBuilders.wildcardQuery("corpName","中国*")); //------------------------------------------------------ request.source(builder); // 执行 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 输出结果 for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getSourceAsMap()); } }
2.5 rang 查询
范围查询,只针对数值类型,对一个field 进行大于或者小于的范围指定
这里的范围是
带等号
的,这里能查询到fee等于5,或者10的,如果想要<
或者>
的效果可以看注释
查询语句:
#rang 查询 POST /sms-logs-index/sms-logs-type/_search { "query": { "range": { "fee": { "gte": 10, # gt: > gte: >= "lte": 20 # lt: < lte: <= } } } }
java代码实现方式:
public void findByRang() throws IOException { // 创建request对象 SearchRequest request = new SearchRequest(index); request.types(type); // 指定查询条件 SearchSourceBuilder builder = new SearchSourceBuilder(); //-------------------------------------------------- builder.query(QueryBuilders.rangeQuery("fee").gt(10).lte(30)); //------------------------------------------------------ request.source(builder); // 执行 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 输出结果 for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getSourceAsMap()); } }
2.6 regexp 查询
正则查询,通过你编写的正则表达式去匹配内容 Ps:prefix wildcard fuzzy 和regexp 查询效率比较低 ,在要求效率比较高时,避免使用
查询语句:
POST /sms-logs-index/sms-logs-type/_search { "query": { "regexp": { "mobile": "156[0-9]{8}" } } }
java代码实现方式:
public void findByRegexp() throws IOException { // 创建request对象 SearchRequest request = new SearchRequest(index); request.types(type); // 指定查询条件 SearchSourceBuilder builder = new SearchSourceBuilder(); //-------------------------------------------------- builder.query(QueryBuilders.regexpQuery("mobile","138[0-9]{8}")); //------------------------------------------------------ request.source(builder); // 执行 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 输出结果 for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getSourceAsMap()); } }
3. 深分页 scroll
ES 对from +size时有限制的,from +size 之和 不能大于1W,超过后 效率会十分低下 原理: from+size ES查询数据的方式, 第一步将用户指定的关键词进行分词, 第二步将词汇去分词库中进行检索,得到多个文档id, 第三步去各个分片中拉去数据, 耗时相对较长 第四步根据score 将数据进行排序, 耗时相对较长 第五步根据from 和size 的值 将部分数据舍弃, 第六步,返回结果。 scroll +size ES 查询数据的方式 第一步将用户指定的关键词进行分词, 第二部将词汇去分词库中进行检索,得到多个文档id, 第三步,将文档的id放在一个上下文中 第四步,根据指定的size的个数去ES中检索指定个数数据,拿完数据的文档id,会从上下文中移除 第五步,如果需要下一页的数据,直接去ES的上下文中找后续内容。 第六步,循环第四步和第五步
Scroll查询方式 不适合做实时查询。
查询方式:
#scroll 查询,返回第一页数据,并将文档id信息存放在ES上下文中,并指定生存时间 POST /sms-logs-index/sms-logs-type/_search?scroll=1m { "query": { "match_all": {} }, "size": 2, "sort": [ # 排序 { "fee": { "order": "desc" } } ] } #根据scroll 查询下一页数据 POST _search/scroll {
#根据第一步得到的scorll_id 去指定 "scroll_id":"DnF1ZXJ5VGhlbkZldGNoAwAAAAAAABbqFk04VlZ1cjlUU2t1eHpsQWNRY1YwWWcAAAAAAAAW7BZNOFZWdXI5VFNrdXh6bEFjUWNWMFlnAAAAAAAAFusWTThWVnVyOVRTa3V4emxBY1FjVjBZZw==", "scroll":"1m" #scorll信息的生存时间 } #删除scroll上下文中的数据 DELETE _search/scroll/DnF1ZXJ5VGhlbkZldGNoAwAAAAAAABchFk04VlZ1cjlUU2t1eHpsQWNRY1YwWWcAAAAAAAAXIBZNOFZWdXI5VFNrdXh6bEFjUWNWMFlnAAAAAAAAFx8WTThWVnVyOVRTa3V4emxBY1FjVjBZZw==
java代码实现方式:
public void scrollSearch() throws IOException { // 1.创建request SearchRequest searchRequest = new SearchRequest(index); searchRequest.types(type); // 2.指定scroll信息,过期时间 searchRequest.scroll(TimeValue.timeValueMinutes(1L)); // 3.指定查询条件 SearchSourceBuilder builder = new SearchSourceBuilder(); builder.size(4); builder.sort("fee", SortOrder.DESC); searchRequest.source(builder); // 4.获取返回结果scrollId,获取source SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT); String scrollId = response.getScrollId(); System.out.println("-------------首页数据---------------------"); for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getSourceAsMap()); } while (true){ // 5.创建scroll request SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId); // 6.指定scroll 有效时间 scrollRequest.scroll(TimeValue.timeValueMinutes(1L)); // 7.执行查询,返回查询结果 SearchResponse scroll = client.scroll(scrollRequest, RequestOptions.DEFAULT); // 8.判断是否查询到数据,查询到输出 SearchHit[] searchHits = scroll.getHits().getHits(); if(searchHits!=null && searchHits.length >0){ System.out.println("-------------下一页数据---------------------"); for (SearchHit hit : searchHits) { System.out.println(hit.getSourceAsMap()); } }else{ // 9.没有数据,结束 System.out.println("-------------结束---------------------"); break; } } // 10.创建 clearScrollRequest ClearScrollRequest clearScrollRequest = new ClearScrollRequest(); // 11.指定scrollId clearScrollRequest.addScrollId(scrollId); //12.删除scroll ClearScrollResponse clearScrollResponse = client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT); // 13.输出结果 System.out.println("删除scroll:"+clearScrollResponse.isSucceeded()); }
4. delete-by-query
根据term,match 等查询方式去删除大量索引 PS:如果你要删除的内容,是index下的大部分数据,推荐创建一个新的index,然后把保留的文档内容,添加到全新的索引
#Delet-by-query 删除 POST /sms-logs-index/sms-logs-type/_delete_by_query { "query": { "range": { "fee": { "lt": 20 } } } }
java代码实现方式:
public void deleteByQuery() throws IOException { // 1.创建DeleteByQueryRequest DeleteByQueryRequest request = new DeleteByQueryRequest(index); request.types(type); // 2.指定条件 request.setQuery(QueryBuilders.rangeQuery("fee").lt(20)); // 3.执行 BulkByScrollResponse response = client.deleteByQuery(request, RequestOptions.DEFAULT); // 4.输出返回结果 System.out.println(response.toString()); }
5.复合查询
5.1 bool查询
复合过滤器,将你的多个查询条件 以一定的逻辑组合在一起, must:所有条件组合在一起,表示 and 的意思 must_not: 将must_not中的条件,全部都不匹配,表示not的意思 should:所有条件用should 组合在一起,表示or 的意思
查询语句:
#查询省份为武汉或北京
#运营商不是联通
#smsContent中包含中国和平安
#bool查询
POST /sms-logs-index/sms-logs-type/_search { "query": { "bool": { "should": [ { "term": { "province": { "value": "北京" } } }, { "term": { "province": { "value": "武汉" } } } ], "must_not": [ { "term": { "operatorId": { "value": "2" } } } ], "must": [ { "match": { "smsContent": "中国" } }, { "match": { "smsContent": "平安" } } ] } } }
java代码实现方式:
public void boolSearch() throws IOException { // 1.创建 searchRequest SearchRequest request = new SearchRequest(index); request.types(type); // 2.指定查询条件 SearchSourceBuilder builder = new SearchSourceBuilder(); BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); // #省是 武汉或者北京 boolQueryBuilder.should(QueryBuilders.termQuery("province","北京")); boolQueryBuilder.should(QueryBuilders.termQuery("province","武汉")); //# 运营商不能是联通 boolQueryBuilder.mustNot(QueryBuilders.termQuery("operatorId",2)); //#smsContent 包含 中国 和 平安 boolQueryBuilder.must(QueryBuilders.matchQuery("smsContent","中国")); boolQueryBuilder.must(QueryBuilders.matchQuery("smsContent","平安")); builder.query(boolQueryBuilder); request.source(builder); // 3.执行查询 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 4.输出结果 for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getSourceAsMap()); } }
5.2 boosting 查询
boosting 查询可以帮助我们去影响查询后的score
positive:只有匹配上positive 查询的内容,才会被放到返回的结果集中 negative: 如果匹配上了positive 也匹配上了negative, 就可以 降低这样的文档score. negative_boost:指定系数,必须小于1 0.5 关于查询时,分数时如何计算的: 搜索的关键字再文档中出现的频次越高,分数越高 指定的文档内容越短,分数越高。 我们再搜索时,指定的关键字也会被分词,这个被分词的内容,被分词库匹配的个数越多,分数就越高。
查询语句
POST /sms-logs-index/sms-logs-type/_search { "query": { "boosting": { "positive": { "match": { "smsContent": "收货安装" } }, "negative": { "match": { "smsContent": "王五" } }, "negative_boost": 0.5 #乘0.5 } } }
java代码实现方式:
public void boostSearch() throws IOException { // 1.创建 searchRequest SearchRequest request = new SearchRequest(index); request.types(type); // 2.指定查询条件 SearchSourceBuilder builder = new SearchSourceBuilder(); BoostingQueryBuilder boost = QueryBuilders.boostingQuery( QueryBuilders.matchQuery("smsContent", "收货安装"), QueryBuilders.matchQuery("smsContent", "王五") ).negativeBoost(0.2f); builder.query(boost); request.source(builder); // 3.执行查询 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 4.输出结果 for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getSourceAsMap()); } }
5.3 filter查询
query 查询:根据你的查询条件,去计算文档的匹配度得到一个分数,并根据分数排序,不会做缓存的。
filter 查询:根据查询条件去查询文档,不去计算分数,而且filter会对经常被过滤的数据进行缓存。
#filter 查询 POST /sms-logs-index/sms-logs-type/_search { "query": { "bool": { "filter": [ { "term": { "corpName": "海尔智家公司" } }, { "range":{ "fee":{ "lte":50 } } } ] } } }
java代码实现方式:
public void filter() throws IOException { // 1.searchRequest SearchRequest searchRequest = new SearchRequest(index); searchRequest.types(type); // 2.指定查询条件 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery(); boolBuilder.filter(QueryBuilders.termQuery("corpName","海尔智家公司")); boolBuilder.filter(QueryBuilders.rangeQuery("fee").gt(20)); sourceBuilder.query(boolBuilder); searchRequest.source(sourceBuilder); // 3.执行 SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT); // 4. 输出结果 for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getSourceAsMap()); System.out.println(hit.getId()+"的分数是:"+hit.getScore()); } }
6 .高亮查询
高亮查询就是用户输入的关键字,以一定特殊样式展示给用户,让用户知道为什么这个结果被检索出来 高亮展示的数据,本身就是文档中的一个field,单独将field以highlight的形式返回给用户 ES提供了一个highlight 属性,他和query 同级别。 frament_size: 指定高亮数据展示多少个字符回来 pre_tags:指定前缀标签<front color="red"> post_tags:指定后缀标签 </font>
查询语句:
POST /sms-logs-index/sms-logs-type/_search { "query": { "match": { "smsContent": "中国李宁" } }, "highlight": { "fields": { "smsContent":{} }, "pre_tags":"<font color='red'>", "post_tags":"</font>", "fragment_size":10 } }
java代码实现方式:
public void highLightQuery() throws IOException { // 1.创建request SearchRequest request = new SearchRequest(index); request.types(type); // 2.指定查询条件,指定高亮 SearchSourceBuilder builder = new SearchSourceBuilder(); builder.query(QueryBuilders.matchQuery("smsContent","团队")); HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("smsContent",10) .preTags("<font colr='red'>") .postTags("</font>"); builder.highlighter(highlightBuilder); request.source(builder); // 3.执行 SearchResponse response = client.search(request, RequestOptions.DEFAULT); //4. 输出结果 for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getHighlightFields().get("smsContent")); } }
public void highLightQuery() throws IOException { // 1.创建request SearchRequest request = new SearchRequest(index); request.types(type); // 2.指定查询条件,指定高亮 SearchSourceBuilder builder = new SearchSourceBuilder(); builder.query(QueryBuilders.matchQuery("smsContent","团队")); HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("smsContent",10) .preTags("<font colr='red'>") .postTags("</font>"); builder.highlighter(highlightBuilder); request.source(builder); // 3.执行 SearchResponse response = client.search(request, RequestOptions.DEFAULT); //4. 输出结果 for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getHighlightFields().get("smsContent")); } }
7.聚合查询
ES的聚合查询和mysql 的聚合查询类似,ES的聚合查询相比mysql 要强大得多。ES提供的统计数据的方式多种多样。
#ES 聚合查询的RSTFul 语法 POST /index/type/_search { "aggs":{ "(名字)agg":{ "agg_type":{ "属性":"值" } } } }
7.1 去重计数查询
去重计数,cardinality 先将返回的文档中的一个指定的field进行去重,统计一共有多少条
# 去重计数 查询 province POST /sms-logs-index/sms-logs-type/_search { "aggs": { "agg": { "cardinality": { "field": "province" } } } }
java代码实现方式:
public void aggCardinalityC() throws IOException { // 1.创建request SearchRequest request = new SearchRequest(index); request.types(type); // 2. 指定使用聚合查询方式 SearchSourceBuilder builder = new SearchSourceBuilder(); builder.aggregation(AggregationBuilders.cardinality("agg").field("province")); request.source(builder); // 3.执行查询 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 4.输出返回结果 Cardinality agg = response.getAggregations().get("provinceAgg"); System.out.println(agg.getValue()); }
7.2 范围统计
统计一定范围内出现的文档个数,比如,针对某一个field 的值再0~100,100~200,200~300 之间文档出现的个数分别是多少 范围统计 可以针对 普通的数值,针对时间类型,针对ip类型都可以响应。 数值 rang 时间 date_rang ip ip_rang
#针对数值方式的范围统计 from 带等于效果 ,to 不带等于效果 POST /sms-logs-index/sms-logs-type/_search { "aggs": { "agg": { "range": { "field": "fee", "ranges": [ { "to": 30 }, { "from": 30, "to": 60 }, { "from": 60 } ] } } } } #时间方式统计 POST /sms-logs-index/sms-logs-type/_search { "aggs": { "agg": { "date_range": { "field": "sendDate", "format": "yyyy", "ranges": [ { "to": "2000" },{ "from": "2000" } ] } } } } #ip 方式 范围统计 POST /sms-logs-index/sms-logs-type/_search { "aggs": { "agg": { "ip_range": { "field": "ipAddr", "ranges": [ { "to": "127.0.0.8" }, { "from": "127.0.0.8" } ] } } } }
java代码实现方式:
public void aggRang() throws IOException { // 1.创建request SearchRequest request = new SearchRequest(index); request.types(type); // 2. 指定使用聚合查询方式 SearchSourceBuilder builder = new SearchSourceBuilder(); builder.aggregation(AggregationBuilders.range("agg").field("fee") .addUnboundedTo(30) .addRange(30,60) .addUnboundedFrom(60)); request.source(builder); // 3.执行查询 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 4.输出返回结果 Range agg = response.getAggregations().get("agg"); for (Range.Bucket bucket : agg.getBuckets()) { String key = bucket.getKeyAsString(); Object from = bucket.getFrom(); Object to = bucket.getTo(); long docCount = bucket.getDocCount(); System.out.println(String.format("key: %s ,from: %s ,to: %s ,docCount: %s",key,from,to,docCount)); } }
7.3 统计聚合
他可以帮你查询指定field 的最大值,最小值,平均值,平方和... 使用 extended_stats
#统计聚合查询 extended_stats POST /sms-logs-index/sms-logs-type/_search { "aggs": { "agg": { "extended_stats": { "field": "fee" } } } }
java代码实现方式:
// java实现 public void aggExtendedStats() throws IOException { // 1.创建request SearchRequest request = new SearchRequest(index); request.types(type); // 2. 指定使用聚合查询方式 SearchSourceBuilder builder = new SearchSourceBuilder(); builder.aggregation(AggregationBuilders.extendedStats("agg").field("fee")); request.source(builder); // 3.执行查询 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 4.输出返回结果 ExtendedStats extendedStats = response.getAggregations().get("agg"); System.out.println("最大值:"+extendedStats.getMaxAsString()+",最小值:"+extendedStats.getMinAsString()); }
8.地图经纬度搜索
#创建一个经纬度索引,指定一个 name ,一个location PUT /map { "settings": { "number_of_shards": 5, "number_of_replicas": 1 }, "mappings": { "map":{ "properties":{ "name":{ "type":"text" }, "location":{ "type":"geo_point" } } } } } #添加测试数据 PUT /map/map/1 { "name":"天安门", "location":{ "lon": 116.403694, "lat":39.914492 } } PUT /map/map/2 { "name":"百望山", "location":{ "lon": 116.26284, "lat":40.036576 } } PUT /map/map/3 { "name":"北京动物园", "location":{ "lon": 116.347352, "lat":39.947468 } }
8.1 ES 的地图检索方式
geo_distance :直线距离检索方式
geo_bounding_box: 以2个点确定一个矩形,获取再矩形内的数据
geo_polygon:以多个点,确定一个多边形,获取多边形的全部数据
#geo_distance POST /map/map/_search { "query": { "geo_distance":{ #确定一个点 "location":{ "lon":116.434739, "lat":39.909843 }, #确定半径 "distance":20000, #指定形状为圆形 "distance_type":"arc" } } }
#geo_bounding_box POST /map/map/_search { "query":{ "geo_bounding_box":{ "location":{ "top_left":{ "lon":116.327805, "lat":39.95499 }, "bottom_right":{ "lon": 116.363162, "lat":39.938395 } } } } }
#geo_polygon
POST /map/map/_search
{
"query":{
"geo_polygon":{
"location":{
# 指定多个点确定 位置
"points":[
{
"lon":116.220296,
"lat":40.075013
},
{
"lon":116.346777,
"lat":40.044751
},
{
"lon":116.236106,
"lat":39.981533
}
]
}
}
}
}
java代码实现方式:
public void GeoPolygon() throws IOException { // 1.创建searchRequest SearchRequest request = new SearchRequest(index); request.types(type); // 2.指定 检索方式 SearchSourceBuilder builder = new SearchSourceBuilder(); List<GeoPoint> points = new ArrayList<>(); points.add(new GeoPoint(40.075013,116.220296)); points.add(new GeoPoint(40.044751,116.346777)); points.add(new GeoPoint(39.981533,116.236106)); builder.query(QueryBuilders.geoPolygonQuery("location",points)); request.source(builder); // 3.执行 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 4.输出结果 for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getSourceAsMap()); } }