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

 

posted @ 2021-03-25 21:09  一场屠夫的战争  阅读(119)  评论(0编辑  收藏  举报