ElasticSearch的各种查询

term&terms查询

term查询

term的查询是代表完全匹配,搜索之前不会对你的关键字进行分词,对你的关键字企业文档分词库中去匹配内容。

#term匹配查询
POST /sms_logs_index/sms_logs_type/_search
{
  "from": 0,   #limit  from,size
  "size": 5,
  "query": {
    "term": {
      "province": {
        "value": "河北"
      }
    }
  }
}
##不会对term中所匹配的值进行分词查询
// java代码实现方式
@Test
public void testQuery() throws IOException {
    //        1 创建Request对象
    SearchRequest request = new SearchRequest(index);
    request.types(type);
    //        2 指定查询条件
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.from(0);
    builder.size(5);
    builder.query(QueryBuilders.termQuery("province", "河北"));

    request.source(builder);
    //        3 执行查询
    RestHighLevelClient client = ESClient.getClient();
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    //        4  获取到_source中的数据
    for (SearchHit hit : response.getHits().getHits()) {
        Map<String, Object> result = hit.getSourceAsMap();
        System.out.println(result);
    }
}

terms查询

相当于in查询

terms: where province = 河北 or province = ? or province = ?

#terms 匹配查询
POST /sms_logs_index/sms_logs_type/_search
{
  "from": 0,
  "size": 5,
  "query": {
    "terms": {
      "province": [
        "河北",
        "河南"
      ]
    }
  }
}
// java代码 terms 查询
@Test
public void test_terms() throws IOException {
    SearchRequest request = new SearchRequest(index);
    request.types(type);

    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.query(QueryBuilders.termsQuery("province","河北","河南"));

    request.source(builder);

    RestHighLevelClient client = ESClient.getClient();
    SearchResponse resp = client.search(request, RequestOptions.DEFAULT);

    for (SearchHit hit : resp.getHits().getHits()){
        System.out.println(hit);
    }
}

match查询

match查询属于高层查询,它会根据你查询字段类型不一样,采用不同的查询方式

match查询,实际底层就是多个term查询,将多个term查询的结果进行了封装

  • 查询的如果是日期或者是数值的话,它会根据你的字符串查询内容转换为日期或者是数值对等
  • 如果查询的内容是一个不可被分的内容(keyword),match查询不会对你的查询的关键字进行分词
  • 如果查询的内容是一个可被分的内容(text),match则会根据指定的查询内容按照一定的分词规则去分词进行查

match_all查询

查询全部内容,不指定任何查询条件。

POST /sms_logs_index/sms_logs_type/_search
{
  "query": {
    "match_all": {}
  }
}
@Test
public void test_match_all() throws IOException {
    // 创建Request  ,放入索引和类型
    SearchRequest request = new SearchRequest(index);
    request.types(type);
    builder.size(20); //es默认查询结果只展示10条,这里可以指定展示的条数
    //指定查询条件
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.query(QueryBuilders.matchAllQuery());
    request.source(builder);
    // 执行查询
    RestHighLevelClient client = ESClient.getClient();
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 获取查询结果,遍历显示
    for (SearchHit hit : response.getHits().getHits()){
        System.out.println(hit);
    }
}

match查询

根据某个Field

POST /sms_logs_index/sms_logs_type/_search
{
  "query": {
    "match": {
      "smsContent": "打车"
    }
  }
}
@Test
public void test_match_field() throws IOException {
    SearchRequest request = new SearchRequest(index);
    request.types(type);
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.query(QueryBuilders.matchQuery("smsContext","打车"));
    request.source(builder);
    RestHighLevelClient client = ESClient.getClient();
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);

    for (SearchHit hit : response.getHits().getHits()){
        System.out.println(hit);
    }

}

布尔match查询

基于一个Filed匹配的内容,采用and或者or的方式进行连接

# 布尔match查询
POST /sms_logs_index/sms_logs_type/_search
{
  "query": {
    "match": {
      "smsContext": {
        "query": "打车 女士",
        "operator": "and"   #or
      }
    }
  }
}
@Test
public void test_match_boolean() throws IOException {
    SearchRequest request = new SearchRequest(index);
    request.types(type);
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.query(QueryBuilders.matchQuery("smsContext","打车 女士").operator(Operator.AND));
    request.source(builder);
    RestHighLevelClient client = ESClient.getClient();
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);

    for (SearchHit hit : response.getHits().getHits()){
        System.out.println(hit);
    }
}

multi_match查询

match针对一个field做检索,multi_match针对多个field进行检索,多个key对应一个text

POST /sms_logs_index/sms_logs_type/_search
{
  "query": {
    "multi_match": {
      "query": "河北",  #指定text
      "fields": ["province","smsContext"] #指定field
    }
  }
}
// java 实现 
@Test
public void test_multi_match() throws IOException {
    SearchRequest request = new SearchRequest(index);
    request.types(type);
    SearchSourceBuilder builder = new SearchSourceBuilder();
    // 查询的文本内容  字段1 字段2 字段3 。。。。。
    builder.query(QueryBuilders.multiMatchQuery("河北", "province", "smsContext"));
    request.source(builder);
    RestHighLevelClient client = ESClient.getClient();
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    for (SearchHit hit : response.getHits().getHits()) {
        System.out.println(hit);
    }
}

其他查询

ID查询

# id查询
GET /sms_logs_index/sms_logs_type/1
GET /索引名/type类型/id
public void test_multi_match() throws IOException {
    GetRequest request = new GetRequest(index,type,"1");
    RestHighLevelClient client = ESClient.getClient();
    GetResponse resp = client.get(request, RequestOptions.DEFAULT);
    System.out.println(resp.getSourceAsMap());
}

ids查询

根据多个id进行查询,类似MySql中的where Id in (id1,id2,id3….)

POST /sms_logs_index/sms_logs_type/_search
{
  "query": {
    "ids": {
      "values": [1,2,3]  #id值
    }
  }
}
//java代码
@Test
public void test_query_ids() throws IOException {
    SearchRequest request = new SearchRequest(index);
    request.types(type);
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.query(QueryBuilders.idsQuery().addIds("1","2","3"));
    request.source(builder);
    RestHighLevelClient client = ESClient.getClient();
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    for (SearchHit hit : response.getHits().getHits()){
        System.out.println(hit.getSourceAsMap());
    }

}

prefix查询

前缀查询,可以通过一个关键字去指定一个Field的前缀,从而查询到指定的文档

POST /sms_logs_index/sms_logs_type/_search
{
  "query": {
    "prefix": {
      "smsContext": {
        "value": "河"
      }
    }
  }
}
# 与 match查询的不同在于,prefix类似mysql中的模糊查询。而match的查询类似于严格匹配查询
# 针对不可分割词
 @Test
public void test_query_prefix() throws IOException {
    SearchRequest request = new SearchRequest(index);
    request.types(type);
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.query(QueryBuilders.prefixQuery("smsContext","河"));
    request.source(builder);
    RestHighLevelClient client = ESClient.getClient();
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    for (SearchHit hit : response.getHits().getHits()){
        System.out.println(hit.getSourceAsMap());
    }
}

fuzzy查询

fuzzy查询:模糊查询,我们可以输入一个字符的大概,ES就可以根据输入的内容大概去匹配一下结果,eg.你可以存在一些错别字

#fuzzy查询
POST /sms_logs_index/sms_logs_type/_search
{
  "query": {
    "fuzzy": {
      "corpName": {
        "value": "盒马生鲜",
        "prefix_length": 2  # 指定前几个字符要严格匹配
      }
    }
  }
}
// 不稳定,查询字段差太多也可能查不到
// java 实现
    @Test
    public void test_query_fuzzy() throws IOException {
        SearchRequest request = new SearchRequest(index);
        request.types(type);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.fuzzyQuery("corpName","盒马生鲜").prefixLength(2));
        request.source(builder);
        RestHighLevelClient client = ESClient.getClient();
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        for (SearchHit hit : response.getHits().getHits()){
            System.out.println(hit.getSourceAsMap());
        }
    }
 // .prefixLength() :指定前几个字符严格匹配

wildcard查询

通配查询,与mysql中的like查询是一样的,可以在查询时,在字符串中指定通配符*和占位符?

#wildcard查询
POST /sms_logs_index/sms_logs_type/_search
{
  "query": {
    "wildcard": {
      "corpName": {
        "value": "*车"   # 可以使用*和?指定通配符和占位符
      }
    }
  }
}
# ?代表一个占位符
# ??代表两个占位符
// java代码
@Test
public void test_query_wildcard() throws IOException {
    SearchRequest request = new SearchRequest(index);
    request.types(type);
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.query(QueryBuilders.wildcardQuery("corpName","*车"));
    request.source(builder);
    RestHighLevelClient client = ESClient.getClient();
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    for (SearchHit hit : response.getHits().getHits()){
        System.out.println(hit.getSourceAsMap());
    }
}

range查询

范围查询,只针对数值类型,对某一个Field进行大于或者小于的范围指定

POST /sms_logs_index/sms_logs_type/_search
{
 "query": {
   "range": {
     "relyTotal": {
       "gte": 0,  
       "lte": 3
     }
   }
 }
}

# 查询范围:[gte,lte]
# 查询范围:(gt,lt)
//java代码
@Test
public void test_query_range() throws IOException {
    SearchRequest request = new SearchRequest(index);
    request.types(type);
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.query(QueryBuilders.rangeQuery("fee").lt(5).gt(2));
    request.source(builder);
    RestHighLevelClient client = ESClient.getClient();
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    for (SearchHit hit : response.getHits().getHits()){
        System.out.println(hit.getSourceAsMap());
    }
}

regexp查询

正则查询,通过你编写的正则表达式去匹配内容

PS: prefix,fuzzy,wildcar和regexp查询效率相对比较低,在对效率要求比较高时,避免去使用

POST /sms_logs_index/sms_logs_type/_search
{
  "query": {
    "regexp": {
      "moible": "109[0-8]{7}"  # 匹配的正则规则
    }
  }
}
//java 代码
@Test
public void test_query_regexp() throws IOException {
    SearchRequest request = new SearchRequest(index);
    request.types(type);
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.query(QueryBuilders.regexpQuery("moible","106[0-9]{8}"));
    request.source(builder);
    RestHighLevelClient client = ESClient.getClient();
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    for (SearchHit hit : response.getHits().getHits()){
        System.out.println(hit.getSourceAsMap());
    }
}

深分页Scroll

ES对from+size有限制,from和size两者之和不能超过1w

原理:

from+size  ES查询数据的方式:
  1  先将用户指定的关键词进行分词处理
 2  将分词去词库中进行检索,得到多个文档的id
 3  去各个分片中拉去指定的数据   耗时
 4  根据数据的得分进行排序       耗时
 5  根据from的值,将查询到的数据舍弃一部分
 6  返回查询结果

Scroll+size    在ES中查询方式
  1  先将用户指定的关键词进行分词处理
 2  将分词去词库中进行检索,得到多个文档的id
 3  将文档的id存放在一个ES的上下文中,ES内存
  4  根据你指定给的size的个数去ES中检索指定个数的数据,拿完数据的文档id,会从上下文中移除
 5  如果需要下一页的数据,直接去ES的上下文中,找后续内容
  6  循环进行4.5操作

缺点,Scroll是从内存中去拿去数据的,不适合做实时的查询,拿到的数据不是最新的

# 执行scroll查询,返回第一页数据,并且将文档id信息存放在ES的上下文中,指定生存时间
POST /sms_logs_index/sms_logs_type/_search?scroll=1m
{
  "query": {
    "match_all": {}
  },
  "size": 2,
  "sort": [
    {
      "fee": {
        "order": "desc"
      }
    }
  ]
}
#查询下一页的数据
POST /_search/scroll
{
  "scroll_id": "DnF1ZXJ5VGhlbkZldGNoAwAAAAAAACSPFnJjV1pHbENVVGZHMmlQbHVZX1JGdmcAAAAAAAAkkBZyY1daR2xDVVRmRzJpUGx1WV9SRnZnAAAAAAAAJJEWcmNXWkdsQ1VUZkcyaVBsdVlfUkZ2Zw==",
  "scoll" :"1m"  #scorll信息的生存时间
}
#删除scroll在ES中上下文的数据
DELETE /_search/scroll/scrill_id
//java代码
@Test
public void test_query_scroll() throws IOException {
    //        1   创建SearchRequest
    SearchRequest request = new SearchRequest(index);
    request.types(type);
    //        2   指定scroll信息,生存时间
    request.scroll(TimeValue.timeValueMinutes(1L));
    //        3   指定查询条件
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.size(2);
    builder.sort("fee",SortOrder.DESC);
    builder.query(QueryBuilders.matchAllQuery());
    //        4 获取返回结果scrollid ,source
    request.source(builder);
    RestHighLevelClient client = ESClient.getClient();
    SearchResponse response = client.search(request,RequestOptions.DEFAULT);
    String scrollId = response.getScrollId();
    System.out.println(scrollId);
    while(true){
        //       5  循环创建SearchScrollRequest
        SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
        // 6 指定scrollid生存时间
        scrollRequest.scroll(TimeValue.timeValueMinutes(1L));
        //        7 执行查询获取返回结果
        SearchResponse scrollResp = client.scroll(scrollRequest, RequestOptions.DEFAULT);
        //        8.判断是否得到数据,输出
        if (scrollResp.getHits().getHits() != null && scrollResp.getHits().getHits().length > 0){
            System.out.println("=======下一页的数据========");
            for (SearchHit hit : scrollResp.getHits().getHits()){
                System.out.println(hit.getSourceAsMap());
            }
        }else{
            //        9.判断没有查询到数据-退出循环
            System.out.println("没得");
            break;
        }
    }
    // 10  创建clearScrollRequest
    ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
    // 11 指定scrollid
    clearScrollRequest.addScrollId(scrollId);
    // 12  删除
    client.clearScroll(clearScrollRequest,RequestOptions.DEFAULT);
}

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
      }
    }
  }
}
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());
}

复合查询

bool查询

复合过滤器,将你的多个查询条件 以一定的逻辑组合在一起,

  • must:所有条件组合在一起,表示 and 的意思
  • must_not:将must_not中的条件,全部都不匹配,表示not的意思
  • should:所有条件用should 组合在一起,表示or 的意思
# 省是 晋城 或者 北京
# 运营商不能是联通
# smsContent 包含 战士 和 的
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": "的"
          }
        }
      ]
    }
  }
}
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());
    }
}

boosting 查询

boosting 查询可以帮助我们去影响查询后的score

  • positive:只有匹配上positive 查询的内容,才会被放到返回的结果集中
  • negative:如果匹配上了positive 也匹配上了negative, 就可以 降低这样的文档score.
  • negative_boost:指定系数,必须小于1 0.5

关于查询时,分数时如何计算的:

  • 搜索的关键字再文档中出现的频次越高,分数越高
  • 指定的文档内容越短,分数越高。
  • 我们再搜索时,指定的关键字也会被分词,这个被分词的内容,被分词库匹配的个数越多,分数就越高。
#boosting 查询
POST /sms-logs-index/sms-logs-type/_search
{
  "query": {
    "boosting": {
      "positive": {
        "match": {
          "smsContent": "战士"
        }
      }, 
      "negative": {
        "match": {
          "smsContent": "团队"
        }
      },
      "negative_boost": 0.2
    }
  }
}
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());
    }
}

filter 查询

query 查询:根据你的查询条件,去计算文档的匹配度得到一个分数,并根据分数排序,不会做缓存的。

filter 查询:根据查询条件去查询文档,不去计算分数,而且filter会对经常被过滤的数据进行缓存。

#filter 查询
POST /sms-logs-index/sms-logs-type/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "corpName": "海尔智家公司"
           }
        },
        {
          "range":{
            "fee":{
              "lte":50
            }
          }
        }
      ]
    }
  }
}
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());
    }
}

高亮查询

高亮查询就是用户输入的关键字,以一定特殊样式展示给用户,让用户知道为什么这个结果被检索出来
高亮展示的数据,本身就是文档中的一个field,单独将field以highlight的形式返回给用户
ES提供了一个highlight 属性,他和query 同级别。
frament_size: 指定高亮数据展示多少个字符回来
pre_tags:指定前缀标签<front color="red">
post_tags:指定后缀标签 </font>

#highlight 高亮查询
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
  }
}
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"));
    }
}

聚合查询

ES的聚合查询和mysql 的聚合查询类似,ES的聚合查询相比mysql 要强大得多。ES提供的统计数据的方式多种多样。

#ES 聚合查询的RSTFul 语法
POST /index/type/_search
{
    "aggs":{
        "(名字)agg":{
            "agg_type":{
                "属性":"值"
            }
        }
    }
}

去重计数聚合查询

去重计数,cardinality 先将返回的文档中的一个指定的field进行去重,统计一共有多少条

# 去重计数 查询 province
POST /sms-logs-index/sms-logs-type/_search
{
  "aggs": {
    "provinceAgg": {
      "cardinality": {
        "field": "province"
      }
    }
  }
}
public void aggCardinalityC() throws IOException {

    // 1.创建request
    SearchRequest request = new SearchRequest(index);
    request.types(type);

    // 2. 指定使用聚合查询方式
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.aggregation(AggregationBuilders.cardinality("provinceAgg").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());
}

范围统计

统计一定范围内出现的文档个数,比如,针对某一个field 的值再0100,100200,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"
          }
        ]
      }
    }
  }
}
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));
    }
}

统计聚合

他可以帮你查询指定field 的最大值,最小值,平均值,平方和...
使用 extended_stats

#统计聚合查询 extended_stats
POST /sms-logs-index/sms-logs-type/_search
{
  "aggs": {
    "agg": {
      "extended_stats": {
        "field": "fee"
      }
    }
  }
}
// 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());
}

其他聚合查询 查看官方文档

https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-aggregations-metrics-weight-avg-aggregation.html

地图经纬度搜索

#创建一个经纬度索引,指定一个 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
  }
}

ES 的地图检索方式

geo_distance :直线距离检索方式
geo_bounding_box: 以2个点确定一个矩形,获取再矩形内的数据
geo_polygon:以多个点,确定一个多边形,获取多边形的全部数据

基于RESTFul 实现地图检索

geo_distance

#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 实现 geo_polygon

public class GeoDemo {
    RestHighLevelClient client =  EsClient.getClient();
    String index = "map";
    String type="map";

    @Test
    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());
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342