ElasticSearch(ES)详解(三)

前言

这章主要详细介绍ES的批量操作、滚动、复合查询等高级操作。


一、ES批量操作

当批量导入数据时,若每条数据都访问一次ES服务器,会造成很大没必要的负担,因此ES提供了Bulk操作,将所有操作封装在一个请求里,一次提交。

(一)Bulk操作

1.控制台操作:

POST _bulk
# 注意在create/update数据输入时千万不要分行,会报错
{"create":{"_index":"student1"}}
{"name":"张三","age":15,"address":"重庆渝北"}
{"create":{"_index":"student1","_id":"1"}}
{"name":"李四","age":17,"address":"北京海淀"}
{"update":{"_index":"student1","_id":"1"}}
{"doc":{"age":"29"}}
{"delete":{"_index":"student1","_id":"jbb4xoEBXFE1Oz4fKGla"}}

2.JAVA API操作

1.初始化集群客户端,这里演示一次,下面操作直接使用

package com.db123;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * @description:
 * @author: DBH123
 * @date: 2022/7/4 10:13
 */
@SpringBootTest
public class ElasticSearchTestPro {
    private RestHighLevelClient client;
    @BeforeAll
    public void before() {
        // 初始化ES集群客户端
        client = new RestHighLevelClient(
                RestClient.builder(
                        // 输入集群主机
                        // 主机1
                        new HttpHost(
                                "node1",
                                9200,
                                "http"
                        ),
                        // 主机2
                        new HttpHost(
                                "node2",
                                9200,
                                "http"
                        ),
                        // 主机3
                        new HttpHost(
                                "node3",
                                9200,
                                "http"
                        )
                )
        );
    }
}

2.Bulk操作

 // bulk
    @Test
    public void bulkTest() throws IOException {
        // 1.创建Bulk请求对象
        BulkRequest bulkRequest = new BulkRequest();
        // 2.创建需要对文档操作的请求对象, 加入bulk请求对象中
        // 2.1 加入文档1
        IndexRequest createRequest = new IndexRequest("student1");
        String str = "{\"name\":\"JAVA测试\",\"age\":15,\"address\":\"重庆渝北\"}";
        createRequest.id("123").source(str , XContentType.JSON);
        bulkRequest.add(createRequest);
        // 2.2 加入文档2
        IndexRequest createRequest1 = new IndexRequest("student1");
        HashMap<String, Object> map1 = new HashMap<>();
        map1.put("name" , "wlw");
        map1.put("age" , 12);
        map1.put("address" , "英国");
        createRequest1.id("234").source(map1);
        bulkRequest.add(createRequest1);
        // 2.3 修改文档
        HashMap<String, Object> map = new HashMap<>();
        map.put("address", "上海浦东");
        UpdateRequest updateRequest = new UpdateRequest("student1", "123").doc(map);
        bulkRequest.add(updateRequest);
        // 2.4 删除文档
        DeleteRequest deleteRequest = new DeleteRequest("student1", "234");
        bulkRequest.add(deleteRequest);
        // 3.提交客户端处理请求
        BulkResponse responses = client.bulk(bulkRequest, RequestOptions.DEFAULT);
    }

记一个出现的异常:java.lang.IllegalArgumentException: The number of object passed must be even but was [1]
出现该异常的原因在修改文档的请求用的Map类型为Map<String , String>,而修改为Map<String , Object>后正常运行。

(二)Curl文件方式导入数据

如果我们想通过文件方式导入大量数据, 则必须在命令行中使用curl了。
完整命令:

$ curl -s -H "Content-Type: application/x-ndjson" -XPOST localhost:9200/_bulk --data-binary "@requests";

Content-Type: application/x-ndjson 可以换为Content-Type: application/json
主要我们要修改为@requests , requests为当前目录下的json文件。


二、ES查询操作

下面展示一个查询的完全体:

GET goods/_search
{
  "query": {
    "query_string": {
      "default_field": "FIELD",
      "query": "this AND that OR thus"
    }
  },
  "sort": [
    {
      "FIELD": {
        "order": "desc"
      }
    }
  ], 
  "from": 0,
  "size": 20,
  "aggs": {
    "NAME": {
      "AGG_TYPE": {
        
      }
    }
  }, 
  "highlight": {
    "fields": {
      "title": {
        "pre_tags": {}
        , "post_tags": {}
      }
    }
    
  }
}

在这里插入图片描述
下面结合这五部分以goods索引为基础进行重点讲解,下面是goods索引映射。

PUT goods
{
	"mappings": {
		"properties": {
			"title": {
				"type": "text",
				"analyzer": "ik_smart"
			},
			"price": { 
				"type": "double"
			},
			"createTime": {
				"type": "date"
			},
			"categoryName": {	
				"type": "keyword"
			},
			"brandName": {	
				"type": "keyword"
			},
	
			"spec": {		
				"type": "object"
			},
			"saleNum": {	
				"type": "integer"
			},
			
			"stock": {	
				"type": "integer"
			}
		}
	}
}

(一)查询操作

1.matchAll

查询索引的全部信息。
控制台操作:


GET goods/_search
{
  "query": {
    "match_all": {}
  }
}

Java 代码

@Test
    public void matchAll() throws IOException {
        // 1.搜索请求创建
        SearchRequest searchRequest = Requests.searchRequest("goods");
        // 2.创建查询条件构造器,封装查询、聚合、分页等信息
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 3. 创建查询条件
        QueryBuilder query = QueryBuilders.matchAllQuery();
        // 4.指定查询条件
        sourceBuilder.query(query);
        // 5.指定条件构造器
        searchRequest.source(sourceBuilder);
        // 6.开始查询
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
        // 7.查看返回结果 具体可以根据控制台返回json字符串操作
        SearchHits hits = search.getHits();
        long totalNumber = hits.getTotalHits().value;
        System.out.println("查询总条数:" + totalNumber);
        SearchHit[] hits1 = hits.getHits();
        for (SearchHit searchHit : hits1) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods.toString());
        }
    }

2.tremQuery

根据词条匹配,使用该模式,查询条件不进行分词。
控制台操作:

GET goods/_search
{
  "query": {
    "term": {
      "categoryName": {
        "value": "手机"
      }
    }
  }
}

Java API 操作:

 // term query
    @Test
    public void termQueryTest() throws IOException {
        // 1.搜索请求创建
        SearchRequest searchRequest = Requests.searchRequest("goods");
        // 2.创建查询条件构造器,封装查询、聚合、分页等信息
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 3. 创建查询条件 及选择查询类型
        QueryBuilder query = QueryBuilders.termQuery("categoryName" , "手机");
        // 4.指定查询条件
        sourceBuilder.query(query);
        // 5.指定条件构造器
        searchRequest.source(sourceBuilder);
        // 6.开始查询
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);

        // 7.查看返回结果 具体可以根据控制台返回json字符串操作
        SearchHits hits = search.getHits();
        long totalNumber = hits.getTotalHits().value;
        System.out.println("查询总条数:" + totalNumber);
        SearchHit[] hits1 = hits.getHits();
        for (SearchHit searchHit : hits1) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods.toString());
        }

    }

3.matchQuery

匹配查询,会将查询条件先进行分词而后逐个查询,将最后结果求并集(这里可以在操作中指定)。
控制台操作:

GET goods/_search
{
  "query": {
    "match": {
      "title": {
        "query": "联通手机", 
        "operator": "and" #确定结果是什么操作 默认or
      }
    }
    
  }
}

Java API操作

  // match
    @Test
    public void matchTest() throws IOException {
        // 1.搜索请求创建
        SearchRequest searchRequest = Requests.searchRequest("goods");
        // 2.创建查询条件构造器,封装查询、聚合、分页等信息
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 3. 创建查询条件 及选择查询类型
        QueryBuilder query = QueryBuilders.matchQuery("title" , "联通手机");
        // 4.指定查询条件
        sourceBuilder.query(query);
        // 5.指定条件构造器
        searchRequest.source(sourceBuilder);
        // 6.开始查询
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);

        // 7.查看返回结果 具体可以根据控制台返回json字符串操作
        SearchHits hits = search.getHits();
        long totalNumber = hits.getTotalHits().value;
        System.out.println("查询总条数:" + totalNumber);
        SearchHit[] hits1 = hits.getHits();
        for (SearchHit searchHit : hits1) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods.toString());
        }
    }

4.模糊查询

当对搜索条件不清楚的时候可以使用模糊查询。

(1)wildcard查询

可以对查询条件使用通配符,比如“手*”(手后面一个或多个)、“手?”(手后面一个字符),注意:若通配符在前面后引发全文扫描
控制台操作:

GET goods/_search
{
  "query": {
    "wildcard": {
      "categoryName": {
        "value": "手*"
      }
    }
  }
}

Java API操作:

// wildcard
    @Test
    public void wildcardTest() throws IOException {
        // 1.搜索请求创建
        SearchRequest searchRequest = Requests.searchRequest("goods");
        // 2.创建查询条件构造器,封装查询、聚合、分页等信息
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 3. 创建查询条件 及选择查询类型
        QueryBuilder query = QueryBuilders.wildcardQuery("title" , "手*");
        // 4.指定查询条件
        sourceBuilder.query(query);
        // 5.指定条件构造器
        searchRequest.source(sourceBuilder);
        // 6.开始查询
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);

        // 7.查看返回结果 具体可以根据控制台返回json字符串操作
        SearchHits hits = search.getHits();
        long totalNumber = hits.getTotalHits().value;
        System.out.println("查询总条数:" + totalNumber);
        SearchHit[] hits1 = hits.getHits();
        for (SearchHit searchHit : hits1) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods.toString());
        }
    }

(2)正则查询

根据正则表达式条件进行查询。
控制台操作:

GET goods/_search
{
  "query": {
    "regexp": {
      "title": "n[0-9].+"
    }
  }
}

Java API操作:

// regexp
    @Test
    public void regexpTest() throws IOException {
        // 1.搜索请求创建
        SearchRequest searchRequest = Requests.searchRequest("goods");
        // 2.创建查询条件构造器,封装查询、聚合、分页等信息
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 3. 创建查询条件 及选择查询类型
        QueryBuilder query = QueryBuilders.regexpQuery("title" , "n[0-9].*");
        // 4.指定查询条件
        sourceBuilder.query(query);
        // 5.指定条件构造器
        searchRequest.source(sourceBuilder);
        // 6.开始查询
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);

        // 7.查看返回结果 具体可以根据控制台返回json字符串操作
        SearchHits hits = search.getHits();
        long totalNumber = hits.getTotalHits().value;
        System.out.println("查询总条数:" + totalNumber);
        SearchHit[] hits1 = hits.getHits();
        for (SearchHit searchHit : hits1) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods.toString());
        }
    }
(3)前缀查询

配置以查询条件开头的文档,对于keyword的支持比较好。
控制台操作:

GET goods/_search
{
  "query": {
    "prefix": {
      "categoryName": "手"
    }
  }
}

Java API操作:

  // prefix
    @Test
    public void prefixTest() throws IOException {
        // 1.搜索请求创建
        SearchRequest searchRequest = Requests.searchRequest("goods");
        // 2.创建查询条件构造器,封装查询、聚合、分页等信息
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 3. 创建查询条件 及选择查询类型
        QueryBuilder query = QueryBuilders.prefixQuery("categoryName" , "手");
        // 4.指定查询条件
        sourceBuilder.query(query);
        // 5.指定条件构造器
        searchRequest.source(sourceBuilder);
        // 6.开始查询
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);

        // 7.查看返回结果 具体可以根据控制台返回json字符串操作
        SearchHits hits = search.getHits();
        long totalNumber = hits.getTotalHits().value;
        System.out.println("查询总条数:" + totalNumber);
        SearchHit[] hits1 = hits.getHits();
        for (SearchHit searchHit : hits1) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods.toString());
        }
    }

5.范围查询

根据数值的范围进行查询,通常对于数字、日期支持使用。
控制台操作:

GET goods/_search
{
  "query": {
    "range": {
      "createTime": {
        "gte": "2015-03-08 20:00:00", 
        "lte": "2015-03-08 22:00:00"
        , "format": "yyyy-MM-dd HH:mm:ss"
        , "time_zone": "-06:00"
      }
    }
  }
}

Java API操作

 // range
    @Test
    public void rangeTest() throws IOException, ParseException {
        // 1.搜索请求创建
        SearchRequest searchRequest = Requests.searchRequest("goods");
        // 2.创建查询条件构造器,封装查询、聚合、分页等信息
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 3. 创建查询条件 及选择查询类型 设置时间上下限
        QueryBuilder query = QueryBuilders
        .rangeQuery("createTime" )
        .format("yyyy-MM-dd HH:mm:ss")
        .lt("2015-03-08 22:00:00")
        .gt("2015-03-08 20:00:00");
        // 4.指定查询条件
        sourceBuilder.query(query);
        // 5.指定条件构造器
        searchRequest.source(sourceBuilder);
        // 6.开始查询
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);

        // 7.查看返回结果 具体可以根据控制台返回json字符串操作
        SearchHits hits = search.getHits();
        long totalNumber = hits.getTotalHits().value;
        System.out.println("查询总条数:" + totalNumber);
        SearchHit[] hits1 = hits.getHits();
        for (SearchHit searchHit : hits1) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods.toString());
        }
    }

6.queryString查询

多条件查询,及将查询条件与多个字段进行match匹配,而后求和(可换)。
控制台操作:


GET goods/_search
{
  "query": {
    "query_string": {
      "fields": ["title" , "brandName" , "categoryName"],
      "query": "联通手机 and 华为手机",
      "default_operator": "AND"
      
    }
  }
}

Java API 操作

 // query string
    @Test
    public void queryStringTest() throws IOException {
        // 1.搜索请求创建
        SearchRequest searchRequest = Requests.searchRequest("goods");
        // 2.创建查询条件构造器,封装查询、聚合、分页等信息
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 3. 创建查询条件 及选择查询类型
        QueryBuilder query = QueryBuilders.queryStringQuery("联通 And 华为手机")
                .field("title")
                .field("brandName")
                .field("categoryName")
                .defaultOperator(Operator.AND);
        // 4.指定查询条件
        sourceBuilder.query(query);
        // 5.指定条件构造器
        searchRequest.source(sourceBuilder);
        // 6.开始查询
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);

        // 7.查看返回结果 具体可以根据控制台返回json字符串操作
        SearchHits hits = search.getHits();
        long totalNumber = hits.getTotalHits().value;
        System.out.println("查询总条数:" + totalNumber);
        SearchHit[] hits1 = hits.getHits();
        for (SearchHit searchHit : hits1) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods.toString());
        }
    }

7.布尔查询

也叫脚本查询,他对多个查询进行拼接。
拼接操作有:
•must(and):条件必须成立

•must_not(not):条件必须不成立

•should(or):条件可以成立

•filter:条件必须成立,性能比must高。不会计算得分

**得分:**即条件匹配度,匹配度越高,得分越高

控制台操作:

GET goods/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "categoryName": {
              "value": "手机"
            }
          }
        },
        {
          "range": {
            "price": {
              "gte": 2000,
              "lte": 3000
            }
          }
        }
      ],
      "must_not": [
        {
          "term": {
            "brandName": {
              "value": "三星"
            }
          }
        }
      ]
    }
  }
}

Java API操作:

 // bool string
    @Test
    public void boolTest() throws IOException {
        // 1.搜索请求创建
        SearchRequest searchRequest = Requests.searchRequest("goods");
        // 2.创建查询条件构造器,封装查询、聚合、分页等信息
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 3. 创建查询条件 及选择查询类型 转型为boolQuery类型
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        // 3.1 添加条件请求
        TermQueryBuilder query1 = QueryBuilders.termQuery("categoryName", "手机");
        query.must(query1);
        // 3.2 添加请求条件
        RangeQueryBuilder query2 = QueryBuilders.rangeQuery("price").gt(3000);
        query.mustNot(query2);
        // 4.指定查询条件
        sourceBuilder.query(query);
        // 5.指定条件构造器
        searchRequest.source(sourceBuilder);
        // 6.开始查询
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);

        // 7.查看返回结果 具体可以根据控制台返回json字符串操作
        SearchHits hits = search.getHits();
        long totalNumber = hits.getTotalHits().value;
        System.out.println("查询总条数:" + totalNumber);
        SearchHit[] hits1 = hits.getHits();
        for (SearchHit searchHit : hits1) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods.toString());
        }
    }

(二)分页控制

ES对查询返回结果是有控制的,默认返回20条,同时自带分页操作。

1.分页

控制台操作:

GET goods/_search
{
  "query": {
    "match_all": {}
  },
  "size": 200, 
  "from": 0
  
}

Java API操作:

 // 分页
    @Test
    public void pagingTest() throws IOException {
        // 1.搜索请求创建
        SearchRequest searchRequest = Requests.searchRequest("goods");
        // 2.创建查询条件构造器,封装查询、聚合、分页等信息
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 2.1 指定分页
        sourceBuilder.size(20);
        sourceBuilder.from(0);
        // 3. 创建查询条件
        QueryBuilder query = QueryBuilders.matchAllQuery();
        // 4.指定查询条件
        sourceBuilder.query(query);
        // 5.指定条件构造器
        searchRequest.source(sourceBuilder);
        // 6.开始查询
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
        // 7.查看返回结果 具体可以根据控制台返回json字符串操作
        SearchHits hits = search.getHits();
        long totalNumber = hits.getTotalHits().value;
        System.out.println("查询总条数:" + totalNumber);
        SearchHit[] hits1 = hits.getHits();
        for (SearchHit searchHit : hits1) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods.toString());
        }
    }

2.滚动

分页,是每次都去查索引,然后对结果进行分页返回,滚动操作一次性将结果查完,放入缓存,直接从缓存中拿出数据。
控制台操作:

# 第一次查询 注意scroll后面为缓存信息保存时间
GET goods/_search?scroll=1m
{
  "query": {
    "match_all": {}
  },
  "size": 10
}

# 第一次scroll操作会返回一个_scroll_id用于下次操作
{
  "_scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAzYWZ3dzNGctM2pSRS1rLTJvSmk0cTlLZw==",
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },

# 利用scroll_id滚动信息
GET _search/scroll?scroll=1m
{
  "scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAJ8gWV1RiN0g5aEZRWHlRbXhJdjdnWWlmZw=="
}

Java操作:

    // 滚动
    @Test
    public void scrollTest() throws IOException {
        // 0.初始化scrollId
        String scrollId = "";
        // 1.搜索请求创建
        SearchRequest searchRequest = Requests.searchRequest("goods");
        // 2.创建查询条件构造器,封装查询、聚合、分页等信息
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 3. 创建查询条件
        QueryBuilder query = QueryBuilders.matchAllQuery();
        // 4.指定查询条件
        sourceBuilder.query(query);
        // 5.判断是否是第一次回滚。
        if (scrollId.isEmpty() || scrollId == ""){
            // 6.第一次回滚
            // 6.1 设置分页大小
            sourceBuilder.size(15);
            // 6.2 设置回滚快照有效时间
            searchRequest.scroll(TimeValue.timeValueMinutes(1));
            // 6.3 发起请求
            SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
            // 6.4 返回scrollId
            scrollId = response.getScrollId();
        }
        // 7.不是第一次返回
        // 7.1 创建回滚请求
        SearchScrollRequest searchScrollRequest = new SearchScrollRequest(scrollId);
        // 7.2 设置有效时间
        searchScrollRequest.scroll(TimeValue.timeValueMinutes(1));
        // 7.3 开始滚动
        SearchResponse response = client.scroll(searchScrollRequest, RequestOptions.DEFAULT);
        // 8.输出结果
        SearchHits hits = response.getHits();
        long totalNumber = hits.getTotalHits().value;
        System.out.println("查询总条数:" + totalNumber);
        SearchHit[] hits1 = hits.getHits();
        for (SearchHit searchHit : hits1) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods.toString());
        }
    }

(三)聚合操作

分为桶聚合、指标聚合
•指标聚合:相当于MySQL的聚合函数。max、min、avg、sum等

•桶聚合:相当于MySQL的 group by 操作。不要对text类型的数据进行分组,会失败
控制台操作:

# 指标操作
GET goods/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
  	# 聚合列别名
    "max_price": {
      "max": {
        "field": "price"
      }
    }
  }
}
# 桶操作
GET goods/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "goods_type": {
      "terms": {
        "field": "categoryName",
        # 显示列表的数量
        "size": 10
      }
    }
  }
}

# 聚合操作的结果会在返回值最后表示
"aggregations" : {
    "goods_type" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 5,
      "buckets" : [
        {
          "key" : "手机",
          "doc_count" : 728
        },
        {
          "key" : "平板电视",
          "doc_count" : 207
        }
      ]
    }
  }

Java API操作:

  // 聚合
    @Test
    public void aggTest() throws IOException {
        // 1.搜索请求创建
        SearchRequest searchRequest = Requests.searchRequest("goods");
        // 2.创建查询条件构造器,封装查询、聚合、分页等信息
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 2.1 创建聚合对象
        AggregationBuilder aggregation = AggregationBuilders
                .terms("brand_type")
                .field("categoryName")
                .size(10);
        //2.2 加入聚合对象
        sourceBuilder.aggregation(aggregation);
        // 3. 创建查询条件
        QueryBuilder query = QueryBuilders.matchAllQuery();
        // 4.指定查询条件
        sourceBuilder.query(query);
        // 5.指定条件构造器
        searchRequest.source(sourceBuilder);
        // 6.开始查询
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
        // 7.查看聚合返回结果
        Aggregations aggregations = search.getAggregations();
        Map<String, Aggregation> stringAggregationMap = aggregations.asMap();
        // 7.1 通过自定义聚合别名获取对象
        Terms brand_type = (Terms)stringAggregationMap.get("brand_type");
        List<? extends Terms.Bucket> buckets = brand_type.getBuckets();
        for (Terms.Bucket bucket : buckets){
            System.out.println("key:" + bucket.getKey());
            System.out.println("doc_count" + bucket.getDocCount());
        }
    }

(四)高亮操作

就是将查询条件,前后加入自定内容或标签,而后和匹配词条一起返回。
控制台操作:

GET goods/_search
{
  "query": {
    "match": {
      "title": "手机"
    }
  },
  "highlight": {
    "fields": {
      "title": {
        "pre_tags": "<div>",
        "post_tags": "</div>"
      },
      "categoryName": {
        "pre_tags": "<div>",
        "post_tags": "</div>"
      }
    }
  }
  
}
# 会在返回结果每条加一个highlight词条
  {
        "_index" : "goods",
        "_type" : "_doc",
        "_id" : "1284053.0",
        "_score" : 0.37477988,
        "_source" : {
          "brandName" : "中国移动",
          "categoryName" : "手机",
          "createTime" : "2015-03-08 21:28:55",
          "id" : 1284053.0,
          "price" : 498.0,
          "saleNum" : 99999.0,
          "spec" : {
            "网络" : "联通3G",
            "机身内存" : "16G"
          },
          "title" : "天语 nibiru 老人手机 土星一号 (T1) 白色 联通3G手机"
        },
        "highlight" : {
          "title" : [
            "天语 nibiru 老人<div>手机</div> 土星一号 (T1) 白色 联通3G<div>手机</div>"
          ]
        }
      },

Java API操作:

// 高亮
    @Test
    public void highlightTest() throws IOException {
        // 1.搜索请求创建
        SearchRequest searchRequest = Requests.searchRequest("goods");
        // 2.创建查询条件构造器,封装查询、聚合、分页等信息
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 2.1 创建高亮生成器
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        // 2.2 定义高亮内容
        highlightBuilder.field("title");
        highlightBuilder.preTags("<tag>");
        highlightBuilder.postTags("</tag>");
        // 2.3 设置
        sourceBuilder.highlighter(highlightBuilder);
        // 3. 创建查询条件
        QueryBuilder query = QueryBuilders.matchQuery("title" , "手机");
        // 4.指定查询条件
        sourceBuilder.query(query);
        // 5.指定条件构造器
        searchRequest.source(sourceBuilder);
        // 6.开始查询
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
        // 7.查看返回高亮结果
        SearchHits hits = search.getHits();
        long totalNumber = hits.getTotalHits().value;
        System.out.println("查询总条数:" + totalNumber);
        SearchHit[] hits1 = hits.getHits();
        for (SearchHit searchHit : hits1) {
            Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
            System.out.println(highlightFields.get("title").getFragments()[0]);
        }
    }

(五)排序操作

将结果根据指定字段进行排序。
控制台操作:

GET goods/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "price": {
        "order": "desc"
      }
    }
  ]
}

Java API操作,太简单,自己悟吧。

(六)关于时间的操作

ES中默认的时间存储为date格式,里面还是依靠long型( “createTime” : 1425868398000),若是前端传入的是date类型,那么他会date类型存储。但是一般情况下,若前端传入字符串,ES则需对于字符串进行解析,ES有自己支持的时间类型,但是特别注意ES不支持yyyy-MM-dd HH:mm:ss格式,若要支持,需要在设置mapping的时候指定date解析格式:

			"createTime": {
				"type": "date",
				"format": "yyyy-MM-dd HH:mm:ss||yyyy年MM月dd日" 
			},

还要注意,存入ES中的时间需要加上时区信息,因为es计算的时间和我们要相差8小时
因此在导入时:

   @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" , timezone = "GTM+8")
    private String createTime;

如果利用range范围查询时间 可以利用format来对输入的值进行解析

GET goods/_search
{
  "query": {
    "range": {
      "createTime": {
        "gte": "2015-03-08 20:00:00", 
        "lte": "2015-03-08 22:00:00",
         "format": "yyyy-MM-dd HH:mm:ss",
         "time_zone": "-06:00" #通过自己试验,-6可以查到
      
   
      }
    }
  }
}

三、索引的迁移及别名

由于ES不能更改mapping,所有当有需求对mapping进行修改时,比如将date改为keyword类型,这时只有新建一个索引,并将老的索引进行迁移,且可以对新的索引取别名为老索引名字,这样第三方操作不会变动,下面进行演示:

# 创建索引
PUT index
{
  "mappings": {
    "properties": {
      "time" : {
        "type": "date"
      }
    }
  } 
}

# 添加数据
POST _bulk
{"create" : {"_index":"index"}}
{"time" : "2012-12-30"}
{"create" : {"_index":"index"}}
{"time" : "2013-11-30"}
{"create" : {"_index":"index"}}
{"time" : "2015-12-13"}
{"create" : {"_index":"index"}}
{"time" : "2020-12-30"}

# 创建修改索引
PUT index_update
{
  "mappings": {
    "properties": {
      "time" : {
        "type": "keyword"
      }
    }
  } 
}

# 迁移数据
POST _reindex
{
  "source": {
    "index": "index"
  },
  "dest": {
    "index": "index_update"
  }
}

# 删除老索引
DELETE index

# 更改别名
POST index_update/_alias/index

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值