[JAVA]es查询相关java的api

一、基础查询

1.查询关键字

  • term:精确匹配一个字段
  • match:模糊查询或者分词查询一个字段
  • wildcard:使用通配符进行查询

2.查询QueryBuilders

BoolQueryBuilder queryBuilder= QueryBuilders.boolQuery();

①matchAllQuery匹配所有

queryBuilder.matchAllQuery();

②termQuery精准匹配,大小写敏感且不支持

queryBuilder.termQuery("key", value) 一次匹配一个值,完全匹配 queryBuilder.termsQuery("key", obj1, obj2..) 一次匹配多个值

③matchPhraseQuery对中文精确匹配

queryBuilder.matchPhraseQuery("key", value)

④matchQuery("key", Obj) 关键字模糊+分词匹配

queryBuilder.matchQuery(key, value);

⑤multiMatchQuery("text", "field1", "field2"..); 匹配多个字段, 关键字模糊+分词匹配

queryBuilder.multiMatchQuery(value, key1, key2, key3);

⑥组合查询

  • must: AND

  • mustNot: NOT

  • should:: OR

    queryBuilder.must(QueryBuilders.termQuery("user", "kimchy")) .mustNot(QueryBuilders.termQuery("message", "nihao")) .should(QueryBuilders.termQuery("gender", "male"));

形如mysql中where条件 a=8 and (b=3 or b=4)

BoolQueryBuilder builder = QueryBuilders.boolQuery()
  .must(QueryBuilders.termQuery(a,8))
  .must(QueryBuilders.boolQuery()
  .should(QueryBuilders.termQuery(b,3))
  .should(QueryBuilders.termQuery(b,4)));

⑧查询 name字段是张三且code字段为1或2或3(或code以1/2/3开头)

这个查询比较有代表性,可以根据这一种情况的写法扩展出其他多条件范围内的查询写法:

List list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");

第一种
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
QueryBuilder boolQueryBuilder_1= QueryBuilders.termQuery("name", "张三");
boolQueryBuilder.must(boolQueryBuilder_1);
BoolQueryBuilder boolQueryBuilder_2 = QueryBuilders.boolQuery();
list.forEach(temp ->{
		boolQueryBuilder_2.should(QueryBuilders.termQuery("code", temp));
});
boolQueryBuilder.must(boolQueryBuilder_2);

第一种循环遍历list的方法可以把boolQueryBuilder_2.should里面换成前缀查询QueryBuilders.PrefixQuery("code", temp),达到前缀在一个范围内的效果

第二种
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
QueryBuilder boolQueryBuilder_1= QueryBuilders.termQuery("name", "张三");
QueryBuilder boolQueryBuilder_2= QueryBuilders.termsQuery("code", list); //注意此为termsQuery
boolQueryBuilder.must(boolQueryBuilder_1).must(boolQueryBuilder_2);

and和or同时出现时,es的写法:写两个booleanQuery,第一个:boolQuery.must,把所有要and的条件加进去,第二个boolQuery_2.should,把所有要or的条件加进去,再boolQuery.must(boolQuery_2),把boolean2加到boolean1里。

⑨QueryBuilders.wildcardQuery对分词进行模糊匹配

BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
// QueryBuilders.wildcardQuery对分词进行模糊匹配
boolQueryBuilder.must(QueryBuilders.wildcardQuery("name","*胡*"));
Iterable<Student> list = dao.search(boolQueryBuilder);
for(Student s:list){
    System.out.println(s);
}

3.RangeQueryBuilder范围查询,对age进行范围查询

BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.wildcardQuery("name","*漫*"));
// RangeQueryBuilder范围查询,对age进行范围查询
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age");
rangeQueryBuilder.gte(12);
rangeQueryBuilder.lte(12);
boolQueryBuilder.must(rangeQueryBuilder);
Iterable<Student> list = dao.search(boolQueryBuilder);
for(Student s:list){
    System.out.println(s);
}

二、查询

1.使用ElasticsearchRepository

①.普通的

@Autowired
private CustomerBaseRepo customerBaseRepo;

BoolQueryBuilder builder = QueryBuilders.boolQuery();
builder.must(QueryBuilders.termQuery("address", param.getAddress()));
// 方法过时
customerBaseRepo.search(builder,PageRequest.of(param.getPage() - 1, param.getSize()));

②.需要排序

@Autowired
private CustomerBaseRepo customerBaseRepo;

BoolQueryBuilder builder = QueryBuilders.boolQuery();
builder.must(QueryBuilders.termQuery("address", param.getAddress()));
 FieldSortBuilder sort = SortBuilders.fieldSort("lastupdatedon").order(SortOrder.DESC);
NativeSearchQuery query = new NativeSearchQueryBuilder()
  //查询封装
  .withQuery(builder)
  //排序封装
  .withSort(sort)
  .withPageable(PageRequest.of(param.getPage() - 1, param.getSize()))
  .build();
// 方法过时
customerBaseRepo.search(query);

2.使用ElasticsearchRestTemplate

三、详解

1. ElasticsearchTemplate

  • ElasticsearchTemplate 封装ES客户端的一些原生api模板,方便实现一些查询
elasticsearchTemplate.queryForPage   #是查询一个分页列表,用的就是一个对象实例
    NativeSearchQuery                #是springdata中的查询条件
    NativeSearchQueryBuilder         #用于建造一个NativeSearchQuery查询对象
    QueryBuilders                    #设置查询条件,是ES中的类
    SortBuilders                     #设置排序条件
    HighlightBuilder                 #设置高亮显示

2.QueryBuilders

  • QueryBuilders是ES中的查询条件构造器
QueryBuilders.boolQuery          #子方法must可多条件联查
QueryBuilders.termQuery          #精确查询指定字段
QueryBuilders.matchQuery         #按分词器进行模糊查询
QueryBuilders.rangeQuery         #按指定字段进行区间范围查询
#  大于等于      .from    .gte   
#  小于等于      .to      .lte    

3.NativeSearchQuery

  • 原生的查询条件类,用来和ES的一些原生查询方法进行搭配,实现一些比较复杂的查询,最终进行构建.build 可作为ElasticsearchTemplate. queryForPage的参数使用
//构建Search对象
NativeSearchQuery build = new NativeSearchQueryBuilder()
 //条件
 .withQuery(queryBuilder)
 //排序
 .withSort(SortBuilders.fieldSort("id").order(SortOrder.ASC))
 //高亮
 .withHighlightFields(name, ms)
 //分页
 .withPageable(PageRequest.of(pageNum - 1, pageSize))
 //构建
 .build();

AggregatedPage<Goods> aggregatedPage = elasticsearchTemplate.queryForPage(build, Goods.class,new Hig());

//queryForPage 参数一: NativeSearchQuery 封装的查询数据对象;参数二: es对应索引实体类;参数三: 调用高亮工具类

4.总体*查询数据至列表页面*代码,每一步均有解释

    @Autowired
    ElasticsearchTemplate elasticsearchTemplate; 
 
    @RequestMapping(value = "list")
    public String list(@ModelAttribute(value = "vo") QueryVo vo, @RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "5") Integer pageSize, Model model){
        //高亮显示
        String pre = "<span style='color:red'>";
        String post = "</span>";
        //指定要高亮的字段将其加上头尾标签
        HighlightBuilder.Field name = new HighlightBuilder.Field("name").preTags(pre).postTags(post);
        HighlightBuilder.Field ms = new HighlightBuilder.Field("ms").preTags(pre).postTags(post);
        //查询高亮结果不分片,不加此条会按分词器高亮显示(数据变少)
        ms.numOfFragments(1);
 
        //多查询条件  must 可不断添加条件
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        if(StringUtils.isNoneBlank(vo.getName())){
                  //精确查询
                queryBuilder.must(QueryBuilders.termQuery("name.keyword",vo.getName()));
        }
        if(StringUtils.isNoneBlank(vo.getMs())){
                  //模糊查询
                queryBuilder.must(QueryBuilders.matchQuery("ms",vo.getMs()));
        }
        //根据指定字段区间查询   from(gte) 大于等于    to(lte)  小于等于
        RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("price");
        if(vo.getStartpice() != null){
            rangeQuery.from(vo.getStartpice());
        }
        if(vo.getEndpice() != null){
            rangeQuery.to(vo.getEndpice());
        }
        queryBuilder.must(rangeQuery);
 
        //构建Search对象
        NativeSearchQuery build = new NativeSearchQueryBuilder()
                //条件
                .withQuery(queryBuilder)
                //排序
                .withSort(SortBuilders.fieldSort("id").order(SortOrder.ASC))
                //高亮
                .withHighlightFields(name, ms)
                //分页
                .withPageable(PageRequest.of(pageNum - 1, pageSize))
                //构建
                .build();
 
        AggregatedPage<Goods> aggregatedPage = elasticsearchTemplate.queryForPage(build, Goods.class,new Hig());
        //封装分页数据至list集合中
        Page<Goods> page = new Page<>(pageNum, pageSize);
        //填充分页总条数
        page.setTotal(aggregatedPage.getTotalElements());
        //封装至pageinfo内,实现列表
        PageInfo<Goods> pg = new PageInfo<>(page);
        //将es查询到当前页的数据 封装至pg中
        pg.setList(aggregatedPage.getContent());
        
        //传入前端,实现列表页面
        model.addAttribute("pg",pg);
        return "list";
    }

认真看的伙伴可以看出上方我引入了高亮工具类,下面对高亮工具类进行详解(亮点)

//es高亮工具类
public class Hig implements SearchResultMapper {
    /*
    searchResponse 封装高亮查询结果集
    clazz   要封装的es索引对应实体类对象
    pageable
     */
    @Override
    public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> clazz, Pageable pageable) {
        //获取es搜索数据集合对象
        SearchHits hits = searchResponse.getHits();
        //获取高亮搜索后数据的总条数
        long totalHits = hits.getTotalHits();
        //搭建存储数据集合对象
        ArrayList<T> list = new ArrayList<>();
        //判断高亮结果有数据
        if(hits.getHits().length > 0){
            //遍历数据集合
            for (SearchHit searchHit : hits) {
                //获取结果集中所有要高亮字段
                final Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
                //把json串转为目标对象
                T t = JSON.parseObject(searchHit.getSourceAsString(), clazz);
                //获取目标对象的所有属性
                Field[] fields = clazz.getDeclaredFields();
                //遍历属性
                for (Field field : fields) {
                    //打破私有封装
                    field.setAccessible(true);
                    如果高亮的字段和要封装的对象的名字一致则值要重新封装
                    if(highlightFields.containsKey(field.getName())){
                        try {
                            //将查询到的数据进行高亮替换
                            field.set(t,highlightFields.get(field.getName()).fragments()[0].toString());
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
                //存入数据集合中
                list.add(t);
            }
        }
        //返回数据集合,排序对象,集高亮总条数
        return new AggregatedPageImpl<>(list,pageable,totalHits);
    }
}
posted @ 2023-01-10 11:12  未月廿三  阅读(2407)  评论(0编辑  收藏  举报