• ElasticSearch学习十 Java API操作ES


    十、Java API操作ES

    10.1、Springboot整合ES

    导入依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.6.7</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.haojie</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>elasticsearch</name>
        <description>elasticsearch</description>
        <properties>
            <java.version>1.8</java.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    ​
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
    ​
            <!--es-->
            <dependency>
                <groupId>org.elasticsearch</groupId>
                <artifactId>elasticsearch</artifactId>
                <version>7.4.2</version>
            </dependency>
    ​
            <dependency>
                <groupId>org.elasticsearch.client</groupId>
                <artifactId>elasticsearch-rest-client</artifactId>
                <version>7.4.2</version>
            </dependency>
    ​
            <dependency>
                <groupId>org.elasticsearch.client</groupId>
                <artifactId>elasticsearch-rest-high-level-client</artifactId>
                <version>7.4.2</version>
            </dependency>
    ​
        </dependencies>
    ​
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <excludes>
                            <exclude>
                                <groupId>org.projectlombok</groupId>
                                <artifactId>lombok</artifactId>
                            </exclude>
                        </excludes>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    ​
    </project>
    ​

    编写配置类

    package com.haojie.elasticsearch.config;
    ​
    import lombok.Data;
    import org.apache.http.HttpHost;
    import org.elasticsearch.client.RestClient;
    import org.elasticsearch.client.RestHighLevelClient;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    ​
    @Configuration
    @ConfigurationProperties("elasticsearch")
    @Data
    public class ElasticSearchConfig {
    ​
        private String hosts;
    ​
        @Bean
        public RestHighLevelClient restHighLevelClient(){
    ​
    ​
            String[] hostArr=hosts.split(",");
            HttpHost[] httpHosts=new HttpHost[hostArr.length];
            for(int i=0;i<hostArr.length;i++){
                String host=hostArr[i];
                String[] hostTempArr = host.split(":");
                String ip=hostTempArr[0];
                Integer port=Integer.parseInt(hostTempArr[1]);
    ​
                httpHosts[i]=new HttpHost(ip,port,"http");
            }
            RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
                    httpHosts
            ));
            return client;
    ​
        }
    }
    ​

    10.2、操作索引

    添加索引

    单纯的添加索引

    @Test
        public void addIndex() throws IOException {
            // indices是index的复数
            IndicesClient indicesClient = restHighLevelClient.indices();
            // 具体操作,获取返回值
            CreateIndexRequest createIndexRequest = new CreateIndexRequest("itheima");
            CreateIndexResponse createIndexResponse = indicesClient.create(createIndexRequest, RequestOptions.DEFAULT);
    ​
            // 判断返回值结果
            System.out.println(createIndexResponse.isAcknowledged());
        }

     

    创建带数据类型的索引

    @Test
        public void addIndexAndMapping() throws IOException {
            // indices是index的复数
            IndicesClient indicesClient = restHighLevelClient.indices();
            // 具体操作,获取返回值
            CreateIndexRequest createIndexRequest = new CreateIndexRequest("itcast");
            String mappingStr="{\"properties\": {\n" +
                    "      \"address\":{\n" +
                    "        \"type\": \"text\",\n" +
                    "        \"analyzer\": \"ik_max_word\"\n" +
                    "      },\n" +
                    "      \"age\":{\n" +
                    "        \"type\": \"long\"\n" +
                    "      },\n" +
                    "      \"name\":{\n" +
                    "        \"type\": \"keyword\"\n" +
                    "      }\n" +
                    "    }\n" +
                    "  }}";
            createIndexRequest.mapping(mappingStr, XContentType.JSON);
            CreateIndexResponse createIndexResponse = indicesClient.create(createIndexRequest, RequestOptions.DEFAULT);
            // 判断返回值结果
            System.out.println(createIndexResponse.isAcknowledged());
        }

     

    查询索引

    @Test
        public void getIndexAndMapping() throws IOException {
            IndicesClient indicesClient = restHighLevelClient.indices();
            GetIndexRequest getIndexRequest=new GetIndexRequest("itcast");
    ​
            GetIndexResponse getIndexResponse = indicesClient.get(getIndexRequest, RequestOptions.DEFAULT);
    ​
            Map<String, MappingMetaData> mappings = getIndexResponse.getMappings();
            for(String key:mappings.keySet()){
                System.out.println(key+"="+mappings.get(key).getSourceAsMap());
            }
    ​
    ​
    ​
        }

     

    删除索引

    @Test
        public void deleteIndex() throws IOException {
            IndicesClient indicesClient = restHighLevelClient.indices();
            DeleteIndexRequest deleteIndexRequest=new DeleteIndexRequest("itheima");
    ​
            AcknowledgedResponse acknowledgedResponse = indicesClient.delete(deleteIndexRequest, RequestOptions.DEFAULT);
    ​
            System.out.println(acknowledgedResponse.isAcknowledged());
        }

     

    判断索引是否存在

    /**
         * 判断索引是否存在
         * @throws IOException
         */
        @Test
        public void existIndex() throws IOException {
            IndicesClient indicesClient = restHighLevelClient.indices();
            GetIndexRequest getIndexRequest=new GetIndexRequest("itcast");
    ​
    ​
            boolean exists = indicesClient.exists(getIndexRequest, RequestOptions.DEFAULT);
    ​
            System.out.println(exists);
    ​
        }

    10.3、文档操作

    添加文档

    采取Map作为类型添加索引

    /**
         * 使用map作为数据
         * @throws IOException
         */
        @Test
        public void addDoc() throws IOException {
            Map<String,Object> data=new HashMap<>();
            data.put("address","北京昌平");
            data.put("age",35);
            data.put("name","张三");
            IndexRequest indexRequest=new IndexRequest("itcast").id("1").source(data);
            // 添加数据 获取结果
            IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
    ​
            System.out.println(indexResponse.getId());
        }
    ​

     

    普通对象添加

    /**
         * 使用对象作为数据
         * @throws IOException
         */
        @Test
        public void addDocObj() throws IOException {
            Person person=new Person();
            person.setId("2");
            person.setAddress("浙江萧山");
            person.setAge(20);
            person.setName("李四");
            // 将对象转成json
            String data=JSONObject.toJSONString(person);
            System.out.println(data);
            IndexRequest indexRequest=new IndexRequest("itcast").id(person.getId()).source(data,XContentType.JSON);
            // 添加数据 获取结果
            IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
    ​
            System.out.println(indexResponse.getId());
        }

     

    修改文档

    /**
         * id存在则修改,id不存在则添加
         * @throws IOException
         */
        @Test
        public void updateObj() throws IOException {
            Person person=new Person();
            person.setId("2");
            person.setAddress("浙江萧山");
            person.setAge(20);
            person.setName("李四222");
            // 将对象转成json
            String data=JSONObject.toJSONString(person);
            System.out.println(data);
            IndexRequest indexRequest=new IndexRequest("itcast").id(person.getId()).source(data,XContentType.JSON);
            // 添加数据 获取结果
            IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
    ​
            System.out.println(indexResponse.getId());
        }

     

    查询文档

     

    /**
      根据id查询文档
      */
        @Test
        public void findDocById() throws IOException {
            GetRequest getRequest=new GetRequest("itcast");
            getRequest.id("1");
            GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
            System.out.println(getResponse.getSourceAsString());
        }

     

    删除文档

    /**
         * 根据id删除文档
         * @throws IOException
         */
        @Test
        public void deleteDocById() throws IOException {
            DeleteRequest deleteRequest=new DeleteRequest("itcast","1");
            DeleteResponse delete = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
            System.out.println(delete.getId());
        }

    10.4、批量操作

    脚本

    bulk 批量操作就是将文档的增删改查一系列操作,通过一次请求全部完成,减少网络传输次数。

    语法:

    POST  /_bulk
    {"action":{"metadata"}}
    {"data"}
    ​
    action:代表这个操作是什么操作,delete、update等等
    metadata:代表元数据,操作的数据是那个索引、或者索引的id等
    data:是操作的具体数据
    ​
    元数据与数据之间不能换行

    示例:

    POST  /_bulk
    {"delete":{"_index":"person","_id":"5"}}
    {"create":{"_index":"person","_id":"5"}}
    {"name":"六号","age":20,"address":"北京"}
    {"update":{"_index":"person","_id":"2"}}
    {"doc":{"name":"二号"}}

     

    POST /_bulk
    {"delete":{"_index":"person","_id":"5"}}
    {"create":{"_index":"person","_id":"6"}}
    {"name":"俞敏洪","address":"北京海淀"}
    {"update":{"_index":"person","_id":"6"}}
    {"doc":{"name":"老罗"}}

    代码

    @Test
        public void testBulk() throws IOException {
            // 创建bulkRequest ,用于整合所有操作
            BulkRequest bulkRequest=new BulkRequest();
            // 删除1号记录
            DeleteRequest deleteRequest=new DeleteRequest("person","1");
            bulkRequest.add(deleteRequest);
            // 添加8号记录
            Map<String,Object> map=new HashMap<>();
            map.put("name","八号");
            IndexRequest indexRequest=new IndexRequest("person").id("8").source(map);
            bulkRequest.add(indexRequest);
    ​
            //更新3号
            Map<String,Object> map2=new HashMap<>();
            map2.put("name","三号");
            UpdateRequest updateRequest=new UpdateRequest("person","3").doc(map2);
            bulkRequest.add(updateRequest);
            //执行
            restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT);
        }

    10.5、导入数据

    数据准备

    表结构

    CREATE TABLE `goods` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
      `author` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
      `address` varchar(255) DEFAULT NULL,
      `desc` varchar(255) DEFAULT NULL,
      `create_time` date DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=11265 DEFAULT CHARSET=utf8;

    elasticsearch 中索引的创建

    PUT goods
    {
     "mappings": {
       "properties": {
         "name":{
           "type": "keyword"
         },
         "author":{
           "type": "keyword"
         },
         "address":{
           "type":"object"
         },
         "desc":{
           "type": "text",
           "analyzer":"ik_smart"
         },
         "createTime":{
           "type": "date"
         }
       }
     }
    }

    代码

    批量添加的代码

    @Test
        public void importData() throws IOException {
            List<Goods> goodsList = goodsMapper.qryAll();
            BulkRequest bulkRequest=new BulkRequest();
            for(Goods goods:goodsList){
                IndexRequest indexRequest=new IndexRequest("goods");
                // 在elasticsearch中,address字段是Object类,因此java中的address字段需要是对象
                // 因此需要把addressStr这个json类型的字符串转成Map对象
                goods.setAddress(JSONObject.parseObject(goods.getAddressStr(),Map.class));
                indexRequest.id(goods.getId()+"").source(JSONObject.toJSONString(goods),XContentType.JSON);
                bulkRequest.add(indexRequest);
            }
            restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT);
        }

     

    结果

    {
            "_index" : "goods",
            "_type" : "_doc",
            "_id" : "1",
            "_score" : 1.0,
            "_source" : {
              "address" : {
                "province" : "河南",
                "city" : "郑州"
              },
              "addressStr" : """{"province":"河南","city":"郑州"}""",
              "author" : "测试数据",
              "id" : 1,
              "name" : "华为手机",
              "remark" : "北京"
            }
          }

     

    其实在es中,一般不需要addressStr字段,那么在用fastjson进行序列化时,把这个字段不序列化就行了

    package com.haojie.elasticsearch.model;
    ​
    import java.io.Serializable;
    import java.util.Date;
    import java.util.Map;
    ​
    import com.alibaba.fastjson.annotation.JSONField;
    import lombok.Data;
    ​
    /**
     * goods
     * @author 
     */
    @Data
    public class Goods implements Serializable {
        private static final long serialVersionUID = 1L;
        private Integer id;
    ​
        private String name;
    ​
        private String author;
    ​
        private Map<String,Object> address;
        
        @JSONField(serialize = false)
        private String addressStr;
    ​
        private String remark;
    ​
        private Date createTime;
    ​
    ​
    }

     

    10.6、复杂查询

    matchAll查询

    脚本

    matchAll查询:查询所有数据,默认查询只有10条

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

    结果分析

     

     

     

    代码

    @Test
        public void matchAllQry() throws IOException {
            // 构建查询对象,指定查询索引名称
            SearchRequest searchRequest=new SearchRequest("goods");
            // 设置查询条件
            SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
            QueryBuilder query= QueryBuilders.matchAllQuery();
            sourceBuilder.query(query);
            searchRequest.source(sourceBuilder);
            //执行查询
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits searchHits = searchResponse.getHits();
            TotalHits totalHits = searchHits.getTotalHits();
            System.out.println(totalHits.value);
    ​
            SearchHit[] hits = searchHits.getHits();
            List<Goods> goodsList=new ArrayList<>();
            for(SearchHit hit:hits){
                String sourceAsString = hit.getSourceAsString();
                Goods goods = JSONObject.parseObject(sourceAsString, Goods.class);
                goodsList.add(goods);
                System.out.println(goods);
            }
    ​
        }

     

    term查询

    term不会对查询条件进行分词。采用的是等于查询以及字段是keyword的字段。查询语法

    脚本

     

    代码

    @Test
        public void termQuery() throws IOException {
            SearchRequest searchRequest=new SearchRequest("goods");
            SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "华为");
            sourceBuilder.query(termQueryBuilder);
            searchRequest.source(sourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    ​
            SearchHits searchHits = searchResponse.getHits();
            TotalHits totalHits = searchHits.getTotalHits();
            System.out.println(totalHits.value);
    ​
            SearchHit[] hits = searchHits.getHits();
            List<Goods> goodsList=new ArrayList<>();
            for(SearchHit hit:hits){
                String sourceAsString = hit.getSourceAsString();
                Goods goods = JSONObject.parseObject(sourceAsString, Goods.class);
                goodsList.add(goods);
                System.out.println(goods);
            }
    ​
        }

     

    match查询

    脚本

    match查询:

    • 会对查询条件进行分词

    • 然后将分词后的查询条件和索引中的字段进行等值匹配

    • 默认取并集(OR)

     

     

     

     

     

    代码

    @Test
        public void matchQuery() throws IOException {
            SearchRequest searchRequest=new SearchRequest("goods");
            SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", "华为");
            matchQueryBuilder.operator(Operator.AND);
            sourceBuilder.query(matchQueryBuilder);
            searchRequest.source(sourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    ​
            SearchHits searchHits = searchResponse.getHits();
            TotalHits totalHits = searchHits.getTotalHits();
            System.out.println(totalHits.value);
    ​
            SearchHit[] hits = searchHits.getHits();
            List<Goods> goodsList=new ArrayList<>();
            for(SearchHit hit:hits){
                String sourceAsString = hit.getSourceAsString();
                Goods goods = JSONObject.parseObject(sourceAsString, Goods.class);
                goodsList.add(goods);
                System.out.println(goods);
            }
    ​
        }

     

    模糊查询

    模糊查询有三种:

    1. 通配符查询(wildcard):会对查询条件进行分词。还可以使用通配符?(任意单个字符)和*(0或多个字符)

    2. regexp查询:正则查询

    3. prefix查询:前缀查询

    脚本

     

     

    代码

    @Test
        public void wildcardQuery() throws IOException {
            SearchRequest searchRequest=new SearchRequest("goods");
            SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
    ​
    ​
            WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery("name", "华为*");
            sourceBuilder.query(wildcardQueryBuilder);
            searchRequest.source(sourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    ​
            SearchHits searchHits = searchResponse.getHits();
            TotalHits totalHits = searchHits.getTotalHits();
            System.out.println(totalHits.value);
    ​
            SearchHit[] hits = searchHits.getHits();
            List<Goods> goodsList=new ArrayList<>();
            for(SearchHit hit:hits){
                String sourceAsString = hit.getSourceAsString();
                Goods goods = JSONObject.parseObject(sourceAsString, Goods.class);
                goodsList.add(goods);
                System.out.println(goods);
            }
    ​
        }

     

    范围查询

    range范围查询:查询指定字段在指定范围内

    脚本

     

     

     

     

    代码

    @Test
        public void rangeQuery() throws IOException {
            SearchRequest searchRequest=new SearchRequest("goods");
            SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
    ​
            // 范围
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("id");
            // 下限
            rangeQueryBuilder.gt(10);
            // 上限
            rangeQueryBuilder.lt(16);
            sourceBuilder.query(rangeQueryBuilder);
            // 进行排序 所有查询都可以排序
            sourceBuilder.sort("id", SortOrder.DESC);
            searchRequest.source(sourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    ​
            SearchHits searchHits = searchResponse.getHits();
            TotalHits totalHits = searchHits.getTotalHits();
            System.out.println(totalHits.value);
    ​
            SearchHit[] hits = searchHits.getHits();
            List<Goods> goodsList=new ArrayList<>();
            for(SearchHit hit:hits){
                String sourceAsString = hit.getSourceAsString();
                Goods goods = JSONObject.parseObject(sourceAsString, Goods.class);
                goodsList.add(goods);
                System.out.println(goods);
            }
    ​
        }

     

    queryString查询

    queryString查询:

    • 会对查询条件进行分词

    • 然后将分词后的查询条件和索引中的文档字段进行等值匹配

    • 默认取并集(or)

    • 可以指定多个查询字段

    脚本

    GET 索引名称/_search
    {
      "query": {
        
        "query_string": {
          "fields": ["字段1","字段2"],
          "query": "查询条件"
        }
        
      }
    }

     

    GET goods/_search
    {
      "query": {
        "query_string": {
          "fields": ["author","remark","name"], 
          "query": "华为"
        }
      }
    }
    ​
    ​
    GET goods/_search
    {
      "query": {
        "query_string": {
          "fields": ["author","remark","name"], 
          "query": "华为 OR 测试"
        }
      }
    }
    ​

    逻辑运算符要大写

     

    代码

    @Test
        public void queryStringQuery() throws IOException {
            SearchRequest searchRequest=new SearchRequest("goods");
            SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
    ​
            // queryString
            QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery("华为手机").field("name").field("authro").defaultOperator(Operator.AND);
    ​
            sourceBuilder.query(queryStringQueryBuilder);
            // 进行排序 所有查询都可以排序
            sourceBuilder.sort("id", SortOrder.DESC);
            searchRequest.source(sourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    ​
            SearchHits searchHits = searchResponse.getHits();
            TotalHits totalHits = searchHits.getTotalHits();
            System.out.println(totalHits.value);
    ​
            SearchHit[] hits = searchHits.getHits();
            List<Goods> goodsList=new ArrayList<>();
            for(SearchHit hit:hits){
                String sourceAsString = hit.getSourceAsString();
                Goods goods = JSONObject.parseObject(sourceAsString, Goods.class);
                goodsList.add(goods);
                System.out.println(goods);
            }
    ​
        }

     

    布尔查询

    boolQuery:对多个查询条件进行连接

    must(and): 条件必须成立

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

    should(or):条件可以成立

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

    脚本

    GET goods/_search
    {
      "query": {
        "bool": {
          "must": [
            {"term": {
              "name": {
                "value": "华为电脑"
              }
            }
            },
            {
              "match": {
                "remark": "成都"
              }
            }
          ]
        }
      }
    }

     

    因此must会计算得分,因此性能会比较慢,如果第一个条件用来must,建议后面的条件采用filter,filter不会计算得分。

    GET goods/_search
    {
      "query": {
        "bool": {
          "must": [
            {"term": {
              "name": {
                "value": "华为电脑"
              }
            }
            },
            {
              "match": {
                "remark": "成都"
              }
            }
          ],
          "filter": {
            "term": {
              "author": "测试"
            }
          }
        }
      }
    }
    ​

     

     

    ​
    GET goods/_search
    {
      "query": {
        "bool": {
          "must": [
            {"term": {
              "name": {
                "value": "华为电脑"
              }
            }
            },
            {
              "match": {
                "remark": "成都"
              }
            }
          ],
          "filter": [
            {
              "term":{
                "author":{
                  "value":"测试"
                }
              }
            }
            
            ]
        }
      }
    }
    ​

     

    聚合查询

    指标聚合:相当于mysql中的聚合函数。max、min、avg、sum等。

    桶聚合:相当于mysql的group by操作。不要对text类型的数据进行分组,会失败。text类型的数据需要分词,

    脚本

    查询所有name是华为电脑的文档,并且计算最大的id

    ​
    GET goods/_search
    {
      "query": {
        "match": {
          "name": "华为电脑"
        }
      }
      , "aggs": {
        "max_id": {
          "max": {
            "field": "id"
          }
        }
      }
    }
    ​

     

    结果

    "aggregations" : {
        "max_id" : {
          "value" : 11260.0
        }
      }

     

    对author进行分组,不能对remark字段进行分组,因为remark字段是text类型

    GET goods/_search
    {
      "query": {
        "match": {
          "name": "华为电脑"
        }
      }, "aggs": {
        "author_type": {
          "terms": {
            "field": "author",
            "size": 10
          }
        }
      }
    }

     

    结果

    "aggregations" : {
        "author_type" : {
          "doc_count_error_upper_bound" : 0,
          "sum_other_doc_count" : 0,
          "buckets" : [
            {
              "key" : "测试",
              "doc_count" : 1024
            },
            {
              "key" : "王五",
              "doc_count" : 1
            }
          ]
        }
      }

    代码

    @Test
        public void aggQuery() throws IOException {
            SearchRequest searchRequest=new SearchRequest("goods");
            SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
            // matchQuery
            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name","华为电脑");
    ​
           
            sourceBuilder.query(matchQueryBuilder);
            
             // 进行聚合 分组
            // 第一个参数是自定义名称,用于获取数据
            // 第二个字段是进行聚合的字段
            AggregationBuilder agg= AggregationBuilders.terms("author_type").field("author").size(100);
            sourceBuilder.aggregation(agg);
    ​
            // 查询请求与查询条件进行关联
            searchRequest.source(sourceBuilder);
    ​
            //执行查询
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    ​
            SearchHits searchHits = searchResponse.getHits();
            SearchHit[] hits = searchHits.getHits();
            List<Goods> goodsList=new ArrayList<>();
            for(SearchHit hit:hits){
                String sourceAsString = hit.getSourceAsString();
                Goods goods = JSONObject.parseObject(sourceAsString, Goods.class);
                goodsList.add(goods);
                System.out.println(goods);
            }
    ​
            // 获取聚合结果
            Aggregations aggregations = searchResponse.getAggregations();
            Map<String, Aggregation> stringAggregationMap = aggregations.asMap();
            Terms brand_name = (Terms) stringAggregationMap.get("author_type");
    ​
            List<? extends Terms.Bucket> buckets = brand_name.getBuckets();
            for (Terms.Bucket bucket:buckets){
                System.out.println(bucket.getKey());
            }
    ​
        }
    ​

     

    高亮查询

    高亮三要素:

    • 高亮字段

    • 前缀

    • 后缀

    脚本

    GET goods/_search
    {
      "query": {
        "match": {
          "name": "华为电脑"
        }
      }, 
      "highlight": {
        "fields": {
          "name": {
            "pre_tags": "<font color='red'>",
            "post_tags": "</font>"
            
          }
        }
      }
    }

     

    结果:

    {
            "_index" : "goods",
            "_type" : "_doc",
            "_id" : "18",
            "_score" : 2.3984714,
            "_source" : {
              "address" : {
                "province" : "河南",
                "city" : "郑州"
              },
              "author" : "测试",
              "id" : 18,
              "name" : "华为电脑",
              "remark" : "成都"
            },
            "highlight" : {
              "name" : [
                "<font color='red'>华为电脑</font>"
              ]
            }
          },

     

    代码

    @Test
        public void highLightQuery() throws IOException {
            SearchRequest searchRequest=new SearchRequest("goods");
            SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
            // matchQuery
            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name","华为电脑");
    ​
    ​
            sourceBuilder.query(matchQueryBuilder);
    ​
            // 高亮设置
            HighlightBuilder highlightBuilder=new HighlightBuilder();
            highlightBuilder.field("name");
            highlightBuilder.preTags("<font color='red'>");
            highlightBuilder.postTags("</font>");
            sourceBuilder.highlighter(highlightBuilder);
    ​
            // 查询请求与查询条件进行关联
            searchRequest.source(sourceBuilder);
    ​
            //执行查询
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    ​
            SearchHits searchHits = searchResponse.getHits();
            SearchHit[] hits = searchHits.getHits();
            List<Goods> goodsList=new ArrayList<>();
            for(SearchHit hit:hits){
                // 获取查询结果
                String sourceAsString = hit.getSourceAsString();
                Goods goods = JSONObject.parseObject(sourceAsString, Goods.class);
    ​
    ​
                // 获取高亮结果
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField highlightField = highlightFields.get("name");
                Text[] fragments = highlightField.fragments();
                goods.setName(fragments[0].toString());
    ​
                goodsList.add(goods);
                System.out.println(goods);
            }
    ​
    ​
    ​
        }
    ​
    ​

     

    10.7、索引别名和重新创建索引

    随着业务需求的变更,索引的结构可能发生改变。

    ElasticSearch的索引一旦创建,只运行添加字段,不运行改变字段。因为改变字段需要重建倒排索引,影响内部缓存结构,性能太低。

    那么此时,就需要重新创建一个新的索引,并将原有索引的数据导入到新索引中。

     

     

    新建student_index_v1。索引名称必须全部小写。索引名称必须全部小写。

     

     

    如果索引包含大写字母,则会报错

     

     

    有时候为了应对业务的变化,索引结构会变化,这个时候需要重新创建索引,需要把老的索引中的数据拷贝到新创建的索引中,可以采用一个命令 _reindex

     

    脚本

    PUT studnet_index_v1
    {
     "mappings": {
       "properties": {
         "name":{
           "type": "keyword"
         }
       }
     }
    } 
    ​
    ​
    PUT /studnet_index_v1/_doc/1
    {
      "name":"张三"
    }
    ​
    ​
    PUT student_index_v2
    {
      "mappings": {
        "properties": {
          "name":{
            "type": "text"
          }
        }
      }
    }
    ​
    ​
    POST _reindex
    {
      "source": {
        "index": "studnet_index_v1"
      },
      "dest": { 
        "index": "student_index_v2"
      }
    }

     

    运行结果

    {
      "took" : 425,
      "timed_out" : false,
      "total" : 1,
      "updated" : 0,
      "created" : 1,
      "deleted" : 0,
      "batches" : 1,
      "version_conflicts" : 0,
      "noops" : 0,
      "retries" : {
        "bulk" : 0,
        "search" : 0
      },
      "throttled_millis" : 0,
      "requests_per_second" : -1.0,
      "throttled_until_millis" : 0,
      "failures" : [ ]
    }
    ​

     

    索引重建之后,虽然数据以及拷贝到了studnet_index_v2,但是代码中用的还是studnet_index_v1,因此需要对studnet_index_v2做一个别名。

    首先删除索引student_index_v1

    然后给索引student_index_v2起别名,别名叫student_index_v1

    POST student_index_v2/_alias/student_index_v1  //给studnet_index_v2起别名
  • 相关阅读:
    学习Python的体会 (1)
    李敖的管理经
    《inside the c++ object model》读书笔记 之五 构造,解构,拷贝语意学
    《inside the c++ object model》读书笔记 之四 Function 语意学
    《inside the c++ object model》读书笔记 之三:Data语意学
    《inside the c++ object model》读书笔记 之六 执行期语意学
    排序算法插入排序/冒泡排序
    《inside the c++ object model》读书笔记 之七 站在对象模型的尖端
    《inside the c++ object model》读书笔记 之二:构造函数
    《inside the c++ object model》读书笔记 之一:对象
  • 原文地址:https://www.cnblogs.com/cplinux/p/16412628.html
Copyright © 2020-2023  润新知