Springboot整合Elasticsearch 7.X 复杂查询

这里使用Springboot 2.7.12版本,Elasticsearch为7.15.0。

导入依赖

复制代码
       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>

yaml文件配置:

复制代码
  elasticsearch:
      uris: http://localhost:9200

构建实体类,这里为商品的SKU属性表

java 复制代码
@Data
@Document(indexName = "skusearch")
public class SkuEs {

    @Id
    private String id;
    @Field(type = FieldType.Text,analyzer = "ik_smart",searchAnalyzer = "ik_smart")
    private String name;
    private Integer price;
    private Integer num;
    private String image;
    private String images;
    private Date createTime;
    private Date updateTime;
    private String spuId;
    private Integer categoryId;
    //Keyword:不分词
    @Field(type= FieldType.Keyword)
    private String categoryName;
    private Integer brandId;
    @Field(type=FieldType.Keyword)
    private String brandName;
    @Field(type=FieldType.Keyword)
    private String skuAttribute;
    private Integer status;
}

构建service层进行复杂查询:指定条件查询,聚合查询,分页查询,排序查询,高亮等等

java 复制代码
@Service
public class SkuSearchServiceImpl implements SkuSearchService {

   
    @Autowired
    ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public Map<String, Object> search(Map<String, Object> map) {
        if(map!=null&&map.size()>0) {
            NativeSearchQueryBuilder queryBuilder = queryBuilder(map);
            //分组查询
            group(queryBuilder, map);

//            NativeSearchQuery nativeSearchQuery = queryBuilder.build();
            SearchHits<SkuEs> skuEsSearchHits = elasticsearchRestTemplate.search(queryBuilder.build(), SkuEs.class);

            AggregationsContainer<?> aggregations = skuEsSearchHits.getAggregations();
            Aggregations aggregations1 = (Aggregations) aggregations.aggregations();

            Map<String, Object> searchMap = new HashMap<>();
            //解析分组数据
            parseGroup(aggregations1, searchMap);

            //遍历返回的内容进行处理
            List<SearchHit<SkuEs>> searchHits = skuEsSearchHits.getSearchHits();
            //将高亮的内容填充到content中
            List<SkuEs> skuEsList = searchHits.stream().map(i -> {
                Map<String, List<String>> highlightFields = i.getHighlightFields();
                List<String> name = highlightFields.get("name");
                i.getContent().setName(name==null?i.getContent().getName():name.get(0));
                return i.getContent();
            }).collect(Collectors.toList());

            //数据元素
            searchMap.put("list", skuEsList);
            //数据元素总数
            searchMap.put("totalElements", skuEsList.size());
            return searchMap;
        }
        return null;
    }


    public NativeSearchQueryBuilder queryBuilder(Map<String, Object> searchMap){
        NativeSearchQueryBuilder queryBuilder=new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQueryBuilder=new BoolQueryBuilder();
        if(searchMap!=null&&searchMap.size()>0){
            //根据产品关键词进行查询
            String keyword = searchMap.get("keyword").toString();
            if(!StringUtils.isEmpty(keyword))
                boolQueryBuilder.must(QueryBuilders.termQuery("name",keyword));
            //查询指定的品牌
            String brandName=searchMap.get("brand").toString();
            if(!StringUtils.isEmpty(brandName)){
                boolQueryBuilder.must(QueryBuilders.termQuery("brandName",brandName));
            }
            //根据价格进行查询,形式为gteprice-lteprice
            String price = searchMap.get("price").toString();
            if(!StringUtils.isEmpty(price)){
                String[] split = price.split("-");
                boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gte(split[0]));
                if(split.length>1)
                    boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lte(split[1]));
            }
        }
        //根据价格,对于查询出来的产品进行降序排列
        queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
        //分页查询
        queryBuilder.withPageable(PageRequest.of(Integer.parseInt(searchMap.get("current").toString()),Integer.parseInt(searchMap.get("size").toString())));
        queryBuilder.withQuery(boolQueryBuilder);
        //高亮设置
        queryBuilder.withHighlightFields(new HighlightBuilder.Field("name"));
        queryBuilder.withHighlightBuilder(new HighlightBuilder().preTags("<em>").postTags("</em>"));
        return queryBuilder;
    }

    public void group(NativeSearchQueryBuilder queryBuilder,Map<String, Object> searchMap){
        //用户如果没有输入分类条件,则需要将分类搜索出来,作为条件提供给用户
        if(StringUtils.isEmpty(searchMap.get("category"))){
            queryBuilder.withAggregations(AggregationBuilders.terms("categoryList").
                    field("categoryName").size(100));
        }
        //用户如果没有输入品牌条件,则需要将品牌搜索出来,作为条件提供给用户
        if(StringUtils.isEmpty(searchMap.get("brand"))){
            queryBuilder.withAggregations(AggregationBuilders.terms("brandList")
                    .field("brandName").size(100));
        }
    }
    //解析分组数据
    public void parseGroup(Aggregations aggregations, Map<String,Object> resultMap){
        if(aggregations!=null){
            for (Aggregation aggregation : aggregations) {
                ParsedStringTerms terms = (ParsedStringTerms) aggregation;
                String name = terms.getName();
                List<String> collect = terms.getBuckets().stream().map(i -> i.getKeyAsString()).collect(Collectors.toList());
                resultMap.put(name,collect);
            }
        }
    }

}

接口测试:

查询如下:

java 复制代码
{
	"data": {
		"categoryList": [
			"软件研发"
		],
		"brandList": [
			"华为"
		],
		"list": [
			{
				"id": "1318594982227025922",
				"name": "<em>华为</em>Mate40 Pro 32G",
				"price": 114,
				"num": 1228,
				"image": "https://sklll.oss-cn-beijing.aliyuncs.com/secby/af1faf56-b10a-4700-9896-3143a2d1c40f.jpg",
				"images": "https://sklll.oss-cn-beijing.aliyuncs.com/secby/a65bfbe4-21b7-42b2-b5cf-47a9730e0a16.jpg,https://sklll.oss-cn-beijing.aliyuncs.com/secby/fa52ef66-7724-4d6e-bece-15eba0f8f903.jpg,https://sklll.oss-cn-beijing.aliyuncs.com/secby/734f0f17-ac73-45d3-a6bf-83e1569ce887.jpg",
				"createTime": "2020-10-20T08:48:37.000+00:00",
				"updateTime": "2023-12-30T07:41:20.000+00:00",
				"spuId": "1318594982147334146",
				"categoryId": 11159,
				"categoryName": "软件研发",
				"brandId": 11,
				"brandName": "华为",
				"skuAttribute": "{\"就业薪资\":\"10K起\",\"学习费用\":\"2万\"}",
				"status": 1,
				"attrMap": null
			},
			{
				"id": "1318596430360813570",
				"name": "<em>华为</em>Mate40 Pro 32G 1800万像素",
				"price": 112,
				"num": 1227,
				"image": "https://sklll.oss-cn-beijing.aliyuncs.com/secby/9247d041-e940-426c-8e50-06084b631063.jpg",
				"images": "https://sklll.oss-cn-beijing.aliyuncs.com/secby/5f5b7435-6cf2-4797-8f65-d4abff181390.jpg",
				"createTime": "2020-10-20T08:54:22.000+00:00",
				"updateTime": "2023-12-30T07:41:21.000+00:00",
				"spuId": "1318596430293704706",
				"categoryId": 11159,
				"categoryName": "软件研发",
				"brandId": 11,
				"brandName": "华为",
				"skuAttribute": "{\"就业薪资\":\"10K起\",\"学习费用\":\"2万\"}",
				"status": 1,
				"attrMap": null
			},
			{
				"id": "1318596430398562305",
				"name": "<em>华为</em>Mate40 Pro 128G",
				"price": 111,
				"num": 1226,
				"image": "https://sklll.oss-cn-beijing.aliyuncs.com/secby/900a3618-9884-4778-bad9-c6c31eaf3eab.jpg",
				"images": "https://sklll.oss-cn-beijing.aliyuncs.com/secby/5f5b7435-6cf2-4797-8f65-d4abff181390.jpg",
				"createTime": "2020-10-20T08:54:22.000+00:00",
				"updateTime": "2023-12-30T07:41:24.000+00:00",
				"spuId": "1318596430293704706",
				"categoryId": 11159,
				"categoryName": "软件研发",
				"brandId": 11,
				"brandName": "华为",
				"skuAttribute": "{\"就业薪资\":\"10K起\",\"学习费用\":\"2万\"}",
				"status": 1,
				"attrMap": null
			}
		],
		"totalElements": 3
	},
	"code": 20000,
	"message": "操作成功"
}
相关推荐
华科易迅2 分钟前
Spring装配对象方法-注解
java·后端·spring
AwesomeDevin38 分钟前
AI时代,我们的任务不应沉溺于与 AI 聊天,🤔 从“对话式编程”迈向“数字软件工厂”
前端·后端·架构
Victor3561 小时前
MongoDB(60)如何使用explain命令?
后端
Victor3561 小时前
MongoDB(59)如何分析查询性能?
后端
怒放吧德德4 小时前
Spring Boot实战:InfluxDB 2.x简单教程
java·spring boot·后端
indexsunny4 小时前
互联网大厂Java面试实战:核心技术与业务场景深度解析
java·spring boot·hibernate·security·microservices·interview
后端不背锅4 小时前
可观测性体系:日志、指标、链路追踪
后端
苍何4 小时前
把小度音箱接入小龙虾是一种什么体验?
后端
华科易迅5 小时前
Spring AOP
java·后端·spring
架构师沉默5 小时前
Gemini 正式登陆香港,不用翻墙!
java·后端·架构