ElasticSearch高级客户端RestHighLevelClient


ElasticSearch高级客户端RestHighLevelClient

记4个对象

1)导包

<!--引入es的坐标-->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.4.0</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>7.4.0</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.4.0</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.4</version>
</dependency>

2)配置

#配置文件:声明ES的主机、端口
heima:
  host: 192.168.200.128
  port: 9200
/*配置类:连接ES,生成RestHighLevelClient*/

3)代码

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(prefix = "elasticsearch")
public class ElasticSearchConfig {
    private String host;
    private int port;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    @Bean
    public RestHighLevelClient client(){
        return new RestHighLevelClient(RestClient.builder(
                new HttpHost(
                        host,
                        port,
                        "http"
                )
        ));
    }
}

索引库维护

索引库维护:“索引库、映射、文档、域”增删改

1)创建索引库

public void addIndex() throws IOException {
    //1.使用client获取操作索引的对象
    IndicesClient indicesClient = client.indices();
    //2.具体操作,获取返回值
    CreateIndexRequest createRequest = new CreateIndexRequest("goods");
    CreateIndexResponse response = indicesClient.create(createRequest, RequestOptions.DEFAULT);

    //3.根据返回值判断结果
    System.out.println(response.isAcknowledged());
}

2)创建映射

public void addIndexAndMapping() throws IOException {
    //1.使用client获取操作索引的对象
    IndicesClient indicesClient = client.indices();
    //2.具体操作,获取返回值
    CreateIndexRequest createRequest = new CreateIndexRequest("itcast");
    //2.1 设置mappings
    String mapping = "{\n" +
                "\t\"properties\": {\n" +
                "\t\t\"title\": {\n" +
                "\t\t\t\"type\": \"text\",\n" +
                "\t\t\t\"analyzer\": \"ik_smart\"\n" +
                "\t\t},\n" +
                "\t\t\"price\": { \n" +
                "\t\t\t\"type\": \"double\"\n" +
                "\t\t},\n" +
                "\t\t\"createTime\": {\n" +
                "\t\t\t\"type\": \"date\"\n" +
                "\t\t},\n" +
                "\t\t\"categoryName\": {\t\n" +
                "\t\t\t\"type\": \"keyword\"\n" +
                "\t\t},\n" +
                "\t\t\"brandName\": {\t\n" +
                "\t\t\t\"type\": \"keyword\"\n" +
                "\t\t},\n" +
                "\n" +
                "\t\t\"spec\": {\t\t\n" +
                "\t\t\t\"type\": \"object\"\n" +
                "\t\t},\n" +
                "\t\t\"saleNum\": {\t\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t},\n" +
                "\t\t\n" +
                "\t\t\"stock\": {\t\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t}\n" +
                "\t}\n" +
                "}";
    createRequest.mapping(mapping,XContentType.JSON);
    CreateIndexResponse response = indicesClient.create(createRequest, RequestOptions.DEFAULT);

    //3.根据返回值判断结果
    System.out.println(response.isAcknowledged());
}
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"
			}
		}
	}
}

3)添加文档

public void importData() throws IOException {
        //1.查询所有数据,mysql
        List<Goods> goodsList = goodsMapper.findAll();
        //System.out.println(goodsList.size());
        //2.bulk导入
        BulkRequest bulkRequest = new BulkRequest();
        //2.1 循环goodsList,创建IndexRequest添加数据
        for (Goods goods : goodsList) {
            //2.2 设置spec规格信息 Map的数据   specStr:{}
            //goods.setSpec(JSON.parseObject(goods.getSpecStr(),Map.class));
            String specStr = goods.getSpecStr();
            //将json格式字符串转为Map集合
            Map map = JSON.parseObject(specStr, Map.class);
            //设置spec map
            goods.setSpec(map);
            //将goods对象转换为json字符串
            String data = JSON.toJSONString(goods);//map --> {}
            IndexRequest indexRequest = new IndexRequest("goods");
            indexRequest.id(goods.getId()+"").source(data, XContentType.JSON);
            bulkRequest.add(indexRequest);
        }
        BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println(response.status());
    }

高级操作

bulk批量操作

//作用:减少请求次数,提高效率
BulkRequest bulkRequest = new BulkRequest();
client.bulk(bulkRequest,RequestOptions.DEFAULT);
bulkRequest.add()

ES搜索

搜索套路代码

public void search(Map searchMap) throws IOException {
    //1. 构建查询请求对象,指定查询的索引名称
    SearchRequest searchRequest = new SearchRequest("goods");
    //2. 创建查询条件构建器SearchSourceBuilder
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();//多条件拼接,布尔查询构建器
   	//3. 封装查询条件、查询方式
   	//3.1 基础查询(使用QueryBuilders构建的查询对象),使用boolQueryBuilder封装
    if(StringUtils.isNotBlank(searchMap.get("keyword"))){
        QueryBuilder keyword = QueryBuilders.matchQuery("title", searchMap.get("keyword"));
        boolQueryBuilder.filter(keyword);
    }
    ....
    //3.2 高级查询(分页,排序、分组、高亮)
    if(分页判断){
        
    }    
    sourceBuilder.from(curPage);
   	sourceBuilder.size(size);
    if(分组聚合判断){//可以有多个;Aggregation:聚合
        AggregationBuilder agg1 = AggregationBuilders.terms("goods_brands").field("brandName").size(100);
        AggregationBuilder agg2 = AggregationBuilders.terms("goods_category").field("categoryName").size(100);
        ...
        sourceBulider.aggregation(agg1);
        sourceBulider.aggregation(agg2);
    }
    if(StringUtils.isNotBlank(searchMap.get("keyword"))){//高亮判断
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");
        highlightBuilder.preTags("");
        highlightBuilder.postTags("");
        searchSourceBuilder.highlighter(highlightBuilder);
    }
    //4. 整合所有查询条件
    searchSourceBuilder.query(boolQueryBuilder);   
    searchRequest.source(sourceBuilder);
    //5. 使用RestHighLevelClient执行搜索searchRequest
    SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
    //6. 获取搜索结果
    SearchHits searchHits = searchResponse.getHits();
    //6.1 获取总记录数
    long value = searchHits.getTotalHits().value;
    System.out.println("总记录数:"+value);
    List<Goods> goodsList = new ArrayList<>();
    //6.2 数据列表
    SearchHit[] hits = searchHits.getHits();
    for (SearchHit hit : hits) {
        //获取json字符串格式的数据
        String sourceAsString = hit.getSourceAsString();
        //转为java对象
        Goods goods = JSON.parseObject(sourceAsString, Goods.class);
        //6.3 高亮结果
        Map<String, HighlightField> highlightFields = hit.getHighlightFields();
        HighlightField HighlightField = highlightFields.get("title");
        Text[] fragments = HighlightField.fragments();
        //替换为“高亮内容”
        if(fragments != null && fragments.size() > 0){
            goods.setTitle(fragments[0].toString());
        }
        goodsList.add(goods);
    }
    //6.4 分组结果
    // 获取聚合结果
    List brands = new ArrayList();
    Aggregations aggregations = searchResponse.getAggregations();
    Map<String, Aggregation> aggregationMap = aggregations.asMap();
    Terms goods_brands = (Terms) aggregationMap.get("goods_brands");
    List<? extends Terms.Bucket> buckets = goods_brands.getBuckets();
    for (Terms.Bucket bucket : buckets) {
        Object key = bucket.getKey();
        brands.add(key);
    }
    
}

ES支持的查询方式

9用的多

QueryBuilders构建:
    1)match_all 查询所有
        QueryBuilder query = QueryBuilders.matchAllQuery();//查询所有文档
    2)term 词条查询:不分词,精确匹配
        QueryBuilder query = QueryBuilders.termQuery("title","华为");
    3)match 分词查询:先分词,后查询(分词后默认使用"or"连接条件)
        QueryBuilder query = QueryBuilders.macthQuery("title", "华为手机");
    4) wildcard 模糊查询
    	WildcardQueryBuilder query = QueryBuilders.wildcardQuery("title", "华*");
    5) regexp 正则查询
    	 RegexpQueryBuilder query = QueryBuilders.regexpQuery("title", "\\w+(.)*");
    6) prefix 前缀查询
    PrefixQueryBuilder query = QueryBuilders.prefixQuery("brandName", "三");
    7) range 范围查询
    	1)QueryBuilder query = QueryBuilders.rangeQuery("").gte("").lte("");
    	  //范围查询
        2)RangeQueryBuilder query = QueryBuilders.rangeQuery("price");
        //指定下限
       	query.gte(2000);
        //指定上限
        query.lte(3000);
    8) queryString 条件字符串查询(作用:一值多域(输入华为,在title和category等等有,都可查)查询,支持分词)
    QueryStringQueryBuilder query = QueryBuilders.queryStringQuery("华为手机").field("title").field("categoryName").field("brandName").defaultOperator(Operator.AND);
    queryStringQuery支持and和or的连接符;
    simplequeryStringQuery不支持
   	9) bool 布尔查询,多条件拼接的条件构建器.连接的方式有下面4种-----》对8)多条件查询的拼接
   		must:(and)必须满足,计算分值
   		must_not:(not)必须不满足,计算分值
   		should:(or)可以满足,计算分值
   		---------------------------------
   		filter:必须满足,不计算分值(效率高)
   		
   		BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
   		
   		实例:
   		   /**
     * 9,布尔查询:boolQuery
     *  1. 查询品牌名称为:华为
     *  2. 查询标题包含:手机
     *  3. 查询价格在:2000-3000
     */
    @Test
    public void testBoolQuery() throws IOException {


        SearchRequest searchRequest = new SearchRequest("goods");

        SearchSourceBuilder sourceBulider = new SearchSourceBuilder();


        //1.构建boolQuery
        BoolQueryBuilder query = QueryBuilders.boolQuery();

        //2.构建各个查询条件
        //2.1 查询品牌名称为:华为
        QueryBuilder termQuery = QueryBuilders.termQuery("brandName","华为");
        query.must(termQuery);

        //2.2. 查询标题包含:手机
        QueryBuilder matchQuery = QueryBuilders.matchQuery("title","手机");
        query.filter(matchQuery);

        //2.3 查询价格在:2000-3000;gte大于等于;lte小于等于
        QueryBuilder rangeQuery = QueryBuilders.rangeQuery("price");
        ((RangeQueryBuilder) rangeQuery).gte(2000);
        ((RangeQueryBuilder) rangeQuery).lte(3000);
        query.filter(rangeQuery);

        //3.使用boolQuery连接

        sourceBulider.query(query);



        searchRequest.source(sourceBulider);


        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);


        SearchHits searchHits = searchResponse.getHits();
        //获取记录数
        long value = searchHits.getTotalHits().value;
        System.out.println("总记录数:"+value);

        List<Goods> goodsList = new ArrayList<>();
        SearchHit[] hits = searchHits.getHits();
        for (SearchHit hit : hits) {
            String sourceAsString = hit.getSourceAsString();

            //转为java
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);

            goodsList.add(goods);
        }

        for (Goods goods : goodsList) {
            System.out.println(goods);
        }
    }


SearchSourceBuilder构建:
	1)分页
		searchSourceBuilder.from(0)
        searchSourceBuilder.size(10)
	2)排序
		searchSourceBuilder.sort(“field”,SortOrder.DESC|SortOrder.ASC);
	3)高亮(指定高亮域、设置高亮前缀、后缀)
	4)分组聚合
		(指标聚合(max,min,avg,sum)和桶聚合(groupby),桶聚合不能对text类型的使用:例:搜索面板上的品牌)
		  AggregationBuilder agg = AggregationBuilders.terms("goods_brands").field("brandName").size(100);//goods_brands是自己起的名字,brandName桶聚合的字段
        sourceBulider.aggregation(agg);



高亮的代码操作
  /**
     *
     * 11,高亮查询:
     *      1. 设置高亮
     *          * 高亮字段
     *          * 前缀
     *          * 后缀
     *      2. 将高亮了的字段数据,替换原有数据
     */
    @Test
    public void testHighLightQuery() throws IOException {


        SearchRequest searchRequest = new SearchRequest("goods");

        SearchSourceBuilder sourceBulider = new SearchSourceBuilder();

        // 1. 查询title包含手机的数据
        MatchQueryBuilder query = QueryBuilders.matchQuery("title", "手机");

        sourceBulider.query(query);

        //设置高亮
        HighlightBuilder highlighter = new HighlightBuilder();
        //设置三要素(前后缀有默认的<em></em>)
        highlighter.field("title");
        highlighter.preTags("<font color='red'>");
        highlighter.postTags("</font>");


        sourceBulider.highlighter(highlighter);



        // 2. 查询品牌列表
        /*
        参数:
            1. 自定义的名称,将来用于获取数据
            2. 分组的字段
         */
        AggregationBuilder agg = AggregationBuilders.terms("goods_brands").field("brandName").size(100);
        sourceBulider.aggregation(agg);



        searchRequest.source(sourceBulider);


        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);


        SearchHits searchHits = searchResponse.getHits();
        //获取记录数
        long value = searchHits.getTotalHits().value;
        System.out.println("总记录数:"+value);

        List<Goods> goodsList = new ArrayList<>();
        SearchHit[] hits = searchHits.getHits();
        for (SearchHit hit : hits) {
            String sourceAsString = hit.getSourceAsString();

            //转为java
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);

            // 获取高亮结果,替换goods中的title
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField HighlightField = highlightFields.get("title");
            Text[] fragments = HighlightField.fragments();//高亮片段(现在只有一个:是数组的第一个元素);域可能是多值得,所以返回的数组
            //替换
            goods.setTitle(fragments[0].toString());


            goodsList.add(goods);
        }

        for (Goods goods : goodsList) {
            System.out.println(goods);
        }

        // 获取聚合结果
        Aggregations aggregations = searchResponse.getAggregations();

        Map<String, Aggregation> aggregationMap = aggregations.asMap();

        //System.out.println(aggregationMap);
        Terms goods_brands = (Terms) aggregationMap.get("goods_brands");

        List<? extends Terms.Bucket> buckets = goods_brands.getBuckets();

        List brands = new ArrayList();
        for (Terms.Bucket bucket : buckets) {
            Object key = bucket.getKey();
            brands.add(key);
        }

        for (Object brand : brands) {
            System.out.println(brand);
        }

    }




SpringBoot整合ElasticSearch

1)导包

2)配置

3)代码

ElasticSearch扩展

集群:把一个项目拆分成多个功能模块,一个功能模块代码,部署到多台服务器,所有服务器完成相同的功能
	作用:高可用、负载均衡
分布式:把一个项目拆分成多个功能模块,每个功能模块单独部署到一台服务器,协同完成一个流程
	作用:分担存储、计算压力,提升应用响应速度
集群、分布式都是高并发解决方案。

ES集群中相关概念

集群-->(多个)节点(主节点、从节点)-->索引-->主分片、副分片
ES集群自平衡:
	集群中某个节点宕机,把该节点的分片,平衡到其他分片;当宕机服务器重启启动后,再对分片进行自平衡,把分片
	拷贝到新启动的节点。
ES集群分片参考数据(仅供参考):
	分片总数 = 总数据量 / 10G-30G
	节点数 = 分片总数 / 1-3	
脑裂(普遍集群存在的问题):
	概念:在集群中,从节点在选择主节点时,发生意见分歧,产生了多个主节点
	原因:
		1)网络延迟
		2)主节点负载过大,节点假死
		3)JVM内存回收,节点假死
	解决:
		1) 使用内网
		2) ES-主节点专注负责管理,不处理其他请求
		3) ES-JVM内存设置为服务器内存的一半大小

1)索引库维护

(1)准备数据;
(2)创建索引库、映射、导入数据;

2)搜索

-------QueryBuilders.-----------
1)term
2)match
3)range
4)bool
-------SearchSourceBuilder-----------
5)page
6)sort
7)highlight
8)aggregation


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM