springBoot集成elasticsearch(功能篇) 二

我们在 springBoot集成elasticsearch  中完成了集成,但是我们需要知道如何使用。其实es和mysql很相识。

              es->索引->字段

        mysql->表->字段

所以索引和表是一个层级的。

接下来,该说下如何使用。

一:查询索引

    

    /**
     * 查询索引是否存在
     * @param myIndex
     * @return
     */
    public boolean queryIndex(String myIndex) {
        try {
            GetIndexRequest request = new GetIndexRequest(myIndex);

            boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);

            return exists;
        } catch (Exception e) {
            return false;
        }

    }

二:创建索引

   /**
     * 创建索引
     *
     * @return
     */
    public Result addIndex(String myIndex) {
        try {
            //查询索引是否存在
            boolean exists =this.queryIndex(myIndex);

            if (exists) {
                return Result.sendSuccess("索引:" + myIndex + "已经存在");
            }
            //创建索引
            CreateIndexRequest indexRequest = new CreateIndexRequest(myIndex);
            CreateIndexResponse response = client.indices()
                    .create(indexRequest, RequestOptions.DEFAULT);
            boolean flag = response.isAcknowledged();
            if (flag) {
                return Result.sendSuccess("索引:" + myIndex + "创建索引成功!");
            } else {
                return Result.sendSuccess("索引:" + myIndex + "创建索引失败!");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return Result.sendFailure("新增异常");
        }

    }

三:添加文档(相当于向数据库添加数据)


    /**
     * 添加文档
     * @param myIndex  索引
     * @param id  es 中id
     * @param user  数据
     * @return
     */
    public Result addDoc(String myIndex, String id, Object user) {
        try {
            IndexRequest request = new IndexRequest(myIndex);

            String source = JSONObject.toJSONString(user);


            // 手动设置id
            request.id(id);
            request.source(source, XContentType.JSON);
            IndexResponse response = client.index(request, RequestOptions.DEFAULT);
            System.out.println(response.getResult());
            return Result.sendSuccess("索引:" + myIndex + "数据成功!", response.getResult());
        } catch (Exception e) {
            e.printStackTrace();
            return Result.sendFailure("添加数据失败");
        }
    }

四:修改文档

其实和三一样,id一定要有。因为es会检查es中是否存在id已经存在,如果id存在。则更新,如果id不存在,则新增。

五:删除文档

 /**
     * 删除文档
     * @param myIndex
     * @param id
     * @return
     */
    public Result deleteDoc(String myIndex, String id) {
        try {
            DeleteRequest deleteRequest = new DeleteRequest(myIndex, id);
            DeleteResponse response = client.delete(deleteRequest, RequestOptions.DEFAULT);
            return Result.sendSuccess("删除文档成功", response.getResult());
        } catch (Exception e) {
            e.printStackTrace();
            return Result.sendFailure("删除成功!");
        }
    }

六:查询文档

其实查询才是最麻烦的地方,因为这个查询比较多。我们这介绍下分页和查询。查询条件的EsUserDto

  @ApiModelProperty(value = "查询条件")
    private String name;

    @ApiModelProperty(value = "索引")
    private String myIndex;

    @ApiModelProperty(value = "当前页")
    private Integer pageNum;
    @ApiModelProperty(value = "当前页大小")
    private Integer pageSize;

查询组装

 /**
     * 查询文档
     * @param esUser
     * @return
     */
    public Result queryDoc(EsUserDto esUser) {
        try {
            //1:查询条件设置
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            //2:设置分页相关
            sourceBuilder.from((esUser.getPageNum() - 1) * esUser.getPageSize());
            //3:每页查询数据
            sourceBuilder.size(esUser.getPageSize());
            //4:设置条件查询
            BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
            if (esUser.getName() != null) {
                boolBuilder.must(QueryBuilders.matchQuery("name", esUser.getName()));
            }
            boolBuilder.should();
            sourceBuilder.query(boolBuilder);
            //5:按时间排序 降序
            sourceBuilder.sort("createTime", SortOrder.DESC);

            //6:设置索引
            SearchRequest searchRequest = new SearchRequest(esUser.getMyIndex());
            searchRequest.source(sourceBuilder);

            System.out.println("搜索语句是:" + sourceBuilder.toString());
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            System.out.println("查询条件:" + search);
            SearchHits hits = search.getHits();
            SearchHit[] hitsArr = hits.getHits();
            TotalHits totalHits = hits.getTotalHits();
            long total = totalHits.value;
            List<EsUser> userList = new ArrayList<>();

            for (SearchHit documentFields : hitsArr) {
                EsUser esUsers = JSONObject.toJavaObject(JSON.parseObject(documentFields.getSourceAsString()), EsUser.class);
                userList.add(esUsers);
            }
            Map<String, Object> map = new HashMap<>(8);
            map.put("total", total);
            map.put("data", userList);
            return Result.sendSuccess("查询成功", map);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.sendFailure("查询异常!");
        }
    }

上面则查询成功了。

七:实现高亮

public Result searchHigh(EsUserDto esUserDto){
        //1、构造请求对象
        SearchRequest searchRequest = new SearchRequest(esUserDto.getMyIndex());
        //2:search builder
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.matchQuery("name", esUserDto.getName()));
        sourceBuilder.from((esUserDto.getPageNum() - 1) * esUserDto.getPageSize());
        sourceBuilder.size(esUserDto.getPageSize());
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        //3:sort
        sourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));
        //4:highlight
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        HighlightBuilder.Field highlightTitle = new HighlightBuilder.Field("name");
        highlightTitle.preTags("<span class=\"highlight\">");
        highlightTitle.postTags("</span>");
        highlightBuilder.field(highlightTitle);
        sourceBuilder.highlighter(highlightBuilder);
        // add builder into request
        searchRequest.indices(esUserDto.getMyIndex());
        searchRequest.source(sourceBuilder);
        //response
        SearchResponse searchResponse = null;
        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        TimeValue took = searchResponse.getTook();
        //search hits
        SearchHits hits = searchResponse.getHits();
        long totalHits = hits.getTotalHits().value;
        SearchHit[] searchHits = hits.getHits();
        List<EsUser> postList = new ArrayList<>();
        for (SearchHit hit : searchHits) {
            String str = hit.getSourceAsString();
            EsUser esPost = JSONObject.parseObject(str, EsUser.class);
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField highlight = highlightFields.get("name");
            if (highlight != null) {
                Text[] fragments = highlight.fragments();
                String fragmentString = fragments[0].string();
                esPost.setName(fragmentString);
            }
            postList.add(esPost);
        }
        return Result.sendSuccess("查询成功",postList);
    }

}

八:es查询模板

对于es的相关查询,我们可以有一个比较好理解的格式:

1:创建请求对象

   SearchRequest searchRequest = new SearchRequest(this.indexName);

2:构建查询体对象。

 //2、构造查询体对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
   
// 是否查询所有的数据true 是全部数据 false是10000条数据。
        searchSourceBuilder.trackTotalHits(true);

3:条件

 //查询都需要在这个下面boolQueryBuilder.must(xxx);              
 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

bool 可以用来合并多个过滤条件查询结果的布尔逻辑,它包含这如下几个操作符:

  • must : 多个查询条件的完全匹配,相当于 and。
  • must_not ::多个查询条件的相反匹配,相当于 not。
  • should : 至少有一个查询条件匹配, 相当于 or。

      (1):查询条件(eq等方法  )

term主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串(未经分析的文本数据类型)

  boolQueryBuilder.must(QueryBuilders.termQuery(fieldName, fieldValue));

当然,如果想在一个字段匹配多个值的话,可以使用terms,相当于SQL的in语法。

注意: terms是匹配多个

         boolQueryBuilder.must(QueryBuilders.termsQuery(key, value));

其中注意对于value,切记不能是List.因为terms内部方法有一个方法:

   public TermsQueryBuilder(String fieldName, Object... values) {
        this(fieldName, (Iterable)(values != null ? Arrays.asList(values) : (Iterable)null));
    }

他是把请求转成List,如果你是list这样查询的时候就变成

{
"terms":{
    "key":[[list]]
  }
}

所以要判断是否是list,如果是list转成数组,然后执行,如下面这种。

if(value instanceof List){
                        List valuess=(List)value;
                        Object[] array = valuess.toArray();
                        TermsQueryBuilder termsQueryBuilder1 = QueryBuilders.termsQuery(key, array);
                        boolQueryBuilder.must(termsQueryBuilder1);

                    }else{
                        TermsQueryBuilder termsQueryBuilder1 = QueryBuilders.termsQuery(key, value);
                        boolQueryBuilder.must(QueryBuilders.termsQuery(key, value));


                    }

       (2):范围条件

    

range可以理解为SQL中的><符号,其中gt是大于,lt是小于,gte是大于等于,lte是小于等于。

  //构造单个rangeBuilder
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(fieldName);
//大于等于
rangeQueryBuilder.gte(fieldvalue);
//大于
 rangeQueryBuilder.gt(fieldvalue);
//小于等于
 rangeQueryBuilder.lte(fieldvalue);
//小于
 rangeQueryBuilder.lt(fieldvalue);

  boolQueryBuilder.must(rangeQuery);

4:模糊查询

boolQueryBuilder.must(QueryBuilders.wildcardQuery(fieldName,fieldValue));

5:正则表达式

   //正则表达式
 String regStr="xu[0-9]";
 boolQueryBuilder.must(QueryBuilders.regexpQuery(fieldName, regStr));

上面几个个都需要用

    searchSourceBuilder.query(boolQueryBuilder);

还有一个排序

searchSourceBuilder.sort("字段", SortOrder.DESC);

6:聚合

(1)sum(统计某个字段的总和)  (字段类型必须是数值类型)

 String name="sum_name"           
 searchSourceBuilder.aggregation(AggregationBuilders.sum(name).field(fieldName));

(2):max(某个字段中最大值)

 String name="max_name"           
 searchSourceBuilder.aggregation(AggregationBuilders.max(name).field(fieldName));

(3):min(某个字段中最小值)

 String name="min_name"           
 searchSourceBuilder.aggregation(AggregationBuilders.min(name).field(fieldName));

(4):avg平均值

 String name="avg_name"           
 searchSourceBuilder.aggregation(AggregationBuilders.avg(name).field(fieldName));

(5):查询

searchRequest.source(searchSourceBuilder);
//、调用请求
SearchResponse response =restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

SearchHits searchHits = response.getHits();
SearchHit[] hist = searchHits.getHits();

logger.info("total==>" + searchHits.getTotalHits().value);
//将数据转换成指定的数据类型
  for (SearchHit hit : hist) {
                Map map = JSONObject.toJavaObject(JSON.parseObject(hit.getSourceAsString()), Map.class);
                logger.info("map==>" + map);
            }

如果使用了聚合则通过如下来获取聚合数据

//从返回的结果中获取聚合返回的值
String name="avg_name"
ParsedAggregation parsedAggregation = response.getAggregations().get(name);
//转换程需要的格式。根据聚合的类型来决定
ParsedSum parsedSum = (ParsedSum)parsedAggregation;
 
long value=parsedSum.getValue()

7:分页

 (1):非聚合分页

         如果是非聚合分页,只需要      

        searchSourceBuilder.from((rankDto.getPageNum() - 1) * rankDto.getPageSize());
        //每页数据量
        searchSourceBuilder.size(rankDto.getPageSize());

 (2):聚合分页

聚合的分页在聚合aggreation中添加就行了。


        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("sponsor").field("refreshOpenId.keyword").size(9999);

        termsAggregationBuilder.subAggregation(new BucketSortPipelineAggregationBuilder("bucket_field",null).from((rankDto.getPageNum() - 1) * rankDto.getPageSize()).size(rankDto.getPageSize()));

        searchSourceBuilder.aggregation(termsAggregationBuilder);

8:嵌套查询(NestedQueryBuilder)

我们有的时候会遇到嵌套查询

  BoolQueryBuilder nestedBoolQueryBuilder = QueryBuilders.boolQuery();
                if (null != value) {

                    NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery(key.substring(0, key.lastIndexOf(".")), QueryBuilders.termQuery(key, value), ScoreMode.None);
                    nestedBoolQueryBuilder.should(nestedQueryBuilder);
                }
                boolQueryBuilder.must(nestedBoolQueryBuilder);

参考:ElasticSearch

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值