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": "操作成功"
}
相关推荐
mldong3 小时前
C# 开发者也有自己的轻量工作流引擎了:NuGet 装包,5 分钟跑通一条审批流
后端·c#·.net
小小猪的春天4 小时前
Java 手写第一个 MCP Server:Spring AI MCP 半小时跑通
java·人工智能·spring boot·ai编程
爱学堂IT分享5 小时前
鹤翔老师pmp项目管理培训认证考试课 (直播录播题库送学时证明)【共58课时】-51CTO学堂
后端
王的宝库5 小时前
Go 项目结构:从单文件到标准工程布局
开发语言·后端·golang
码事漫谈6 小时前
类型即世界:一个 C++ 程序员的本体论入门
后端
Rain的Java大神之路7 小时前
JavaWeb开发如何解决跨域问题
java·前端·后端·nginx·web安全·面试·运维开发
计算机毕设定制辅导-无忧学长7 小时前
《基于SpringBoot青年公寓出租管理系统的设计与实现》
java·vue.js·spring boot·青年公寓出租管理系统
MetaLite8 小时前
AI编程与工程底座-让AI遵守SpringBoot边界
人工智能·spring boot·ai编程
IT_陈寒9 小时前
Python的多线程居然是个假把式?搞清GIL让我少熬三天夜
前端·人工智能·后端
明月_清风9 小时前
位图与布隆过滤器:海量数据下的"存在性判断"艺术
前端·后端·算法