package com.alatus.search.service.impl; import com.alatus.search.config.MallElasticSearchConfig; import com.alatus.search.constant.EsConstant; import com.alatus.search.service.MallSearchService; import com.alatus.search.vo.SearchParam; import com.alatus.search.vo.SearchResult; import org.apache.commons.lang.StringUtils; import org.apache.lucene.search.join.ScoreMode; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.NestedQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.RangeQueryBuilder; import org.elasticsearch.search.aggregations.AggregationBuilder; import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; import org.elasticsearch.search.sort.SortOrder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.IOException; @Service public class MallSearchServiceImpl implements MallSearchService { @Autowired private RestHighLevelClient client; @Override public SearchResult search(SearchParam searchParam) { // 动态构建出查询所需要的DSL语句 SearchResult searchResult = null; // 准备检索请求 SearchRequest searchRequest = buildSearchRequest(searchParam); try { // 执行查询检索请求 SearchResponse response = client.search(searchRequest, MallElasticSearchConfig.COMMON_OPTIONS); // 分析响应数据并封装成返回的数据 searchResult = buildSearchResult(); } catch (IOException e) { throw new RuntimeException(e); } return null; } private SearchResult buildSearchResult() { return null; } //准备检索请求 private SearchRequest buildSearchRequest(SearchParam searchParam) { // 构建DSL语句 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); // 查询条件,模糊查询,过滤,按照属性,分类品牌,价格区间,库存 // 构建了bool-query BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); // must if(!StringUtils.isEmpty(searchParam.getKeyword())){ boolQuery.must(QueryBuilders.matchQuery("skuTitle",searchParam.getKeyword())); } // filter按照三级分类ID查询 if(searchParam.getCatalog3Id()!=null){ boolQuery.filter(QueryBuilders.termQuery("catalogId",searchParam.getCatalog3Id())); } // filter按照品牌ID查询 if(searchParam.getBrandId()!=null && !searchParam.getBrandId().isEmpty()){ boolQuery.filter(QueryBuilders.termsQuery("brandId",searchParam.getBrandId())); } // filter按照属性ID查询 if(searchParam.getAttrs()!=null && !searchParam.getAttrs().isEmpty()){ for (String attrStr : searchParam.getAttrs()) { BoolQueryBuilder nestedBoolQuery = QueryBuilders.boolQuery(); String[] attr = attrStr.split("_"); String attrId = attr[0];//属性ID String[] attrValues = attr[1].split(":");//属性值 nestedBoolQuery.must(QueryBuilders.termQuery("attrs.attrId",attrId)); nestedBoolQuery.must(QueryBuilders.termsQuery("attrs.attrValue",attrValues)); // 每一个都必须有一个嵌入式的查询 NestedQueryBuilder attrs = QueryBuilders.nestedQuery("attrs", nestedBoolQuery, ScoreMode.None); boolQuery.filter(attrs); } } // 按照库存进行查询 if(searchParam.getHasStock()!=null){ boolQuery.filter(QueryBuilders.termQuery("hasStock", searchParam.getHasStock()==1)); } // 按照价格区间 if(!StringUtils.isEmpty(searchParam.getSkuPrice())){ RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("skuPrice"); String[] price = searchParam.getSkuPrice().split("_"); if(price.length == 2){ rangeQuery.gte(price[0]).lte(price[1]); } else if (price.length == 1) { if(searchParam.getSkuPrice().startsWith("_")){ rangeQuery.lte(price[0]); } else if(searchParam.getSkuPrice().endsWith("_")){ rangeQuery.gte(price[0]); } } boolQuery.filter(rangeQuery); } // 把所有条件全部封装 sourceBuilder.query(boolQuery); // 排序 if(!StringUtils.isEmpty(searchParam.getSort())){ String sort = searchParam.getSort(); String[] sortString = sort.split("_"); sourceBuilder.sort(sortString[0],sortString[1].equalsIgnoreCase("asc")?SortOrder.ASC:SortOrder.DESC); } // 分页 if(searchParam.getPageNum()!=null){ sourceBuilder.from((searchParam.getPageNum()-1)*EsConstant.PRODUCT_PAGESIZE); sourceBuilder.size(EsConstant.PRODUCT_PAGESIZE); } // 高亮 if (!StringUtils.isEmpty(searchParam.getKeyword())){ HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("skuTitle"); highlightBuilder.preTags("<b style='color:red'>"); highlightBuilder.postTags("</b>"); sourceBuilder.highlighter(highlightBuilder); } // 品牌聚合 TermsAggregationBuilder brandAgg = AggregationBuilders.terms("brand_agg").field("brandId").size(50); // 品牌聚合的品牌名字子聚合 brandAgg.subAggregation(AggregationBuilders.terms("brand_name_agg").field("brandName").size(1)); // 品牌聚合的品牌图片子聚合 brandAgg.subAggregation(AggregationBuilders.terms("brand_img_agg").field("brandImg").size(1)); // 把品牌聚合放里面 sourceBuilder.aggregation(brandAgg); // 分类聚合 TermsAggregationBuilder catalogAgg = AggregationBuilders.terms("catalog_agg").field("catalogId").size(50); // 分类聚合的品牌名字子聚合 catalogAgg.subAggregation(AggregationBuilders.terms("catalog_name_agg").field("catalogName").size(1)); // 把分类聚合放里面 sourceBuilder.aggregation(catalogAgg); // 属性聚合 NestedAggregationBuilder attrAgg = AggregationBuilders.nested("attrAgg", "attrs"); // 属性ID聚合查询 TermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attr_id_agg").field("attrs.attrId").size(50); // 属性名子聚合 attrIdAgg.subAggregation(AggregationBuilders.terms("attr_name_agg").field("attrs.attrName").size(1)); // 属性值子聚合 attrIdAgg.subAggregation(AggregationBuilders.terms("attr_value_agg").field("attrs.attrValue").size(50)); // 把属性ID聚合查询放进属性内嵌查询 attrAgg.subAggregation(attrIdAgg); // 把属性聚合放里面 sourceBuilder.aggregation(attrAgg); System.out.println(sourceBuilder); return new SearchRequest(new String[]{EsConstant.PRODUCT_INDEX},sourceBuilder); } }
package com.alatus.search.service.impl; import com.alatus.search.config.MallElasticSearchConfig; import com.alatus.search.constant.EsConstant; import com.alatus.search.service.MallSearchService; import com.alatus.search.vo.SearchParam; import com.alatus.search.vo.SearchResult; import org.apache.commons.lang.StringUtils; import org.apache.lucene.search.join.ScoreMode; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.NestedQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.RangeQueryBuilder; import org.elasticsearch.search.aggregations.AggregationBuilder; import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; import org.elasticsearch.search.sort.SortOrder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.IOException; @Service public class MallSearchServiceImpl implements MallSearchService { @Autowired private RestHighLevelClient client; @Override public SearchResult search(SearchParam searchParam) { // 动态构建出查询所需要的DSL语句 SearchResult searchResult = null; // 准备检索请求 SearchRequest searchRequest = buildSearchRequest(searchParam); try { // 执行查询检索请求 SearchResponse response = client.search(searchRequest, MallElasticSearchConfig.COMMON_OPTIONS); // 分析响应数据并封装成返回的数据 searchResult = buildSearchResult(); } catch (IOException e) { throw new RuntimeException(e); } return null; } private SearchResult buildSearchResult() { return null; } //准备检索请求 private SearchRequest buildSearchRequest(SearchParam searchParam) { // 构建DSL语句 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); // 查询条件,模糊查询,过滤,按照属性,分类品牌,价格区间,库存 // 构建了bool-query BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); // must if(!StringUtils.isEmpty(searchParam.getKeyword())){ boolQuery.must(QueryBuilders.matchQuery("skuTitle",searchParam.getKeyword())); } // filter按照三级分类ID查询 if(searchParam.getCatalog3Id()!=null){ boolQuery.filter(QueryBuilders.termQuery("catalogId",searchParam.getCatalog3Id())); } // filter按照品牌ID查询 if(searchParam.getBrandId()!=null && !searchParam.getBrandId().isEmpty()){ boolQuery.filter(QueryBuilders.termsQuery("brandId",searchParam.getBrandId())); } // filter按照属性ID查询 if(searchParam.getAttrs()!=null && !searchParam.getAttrs().isEmpty()){ for (String attrStr : searchParam.getAttrs()) { BoolQueryBuilder nestedBoolQuery = QueryBuilders.boolQuery(); String[] attr = attrStr.split("_"); String attrId = attr[0];//属性ID String[] attrValues = attr[1].split(":");//属性值 nestedBoolQuery.must(QueryBuilders.termQuery("attrs.attrId",attrId)); nestedBoolQuery.must(QueryBuilders.termsQuery("attrs.attrValue",attrValues)); // 每一个都必须有一个嵌入式的查询 NestedQueryBuilder attrs = QueryBuilders.nestedQuery("attrs", nestedBoolQuery, ScoreMode.None); boolQuery.filter(attrs); } } // 按照库存进行查询 if(searchParam.getHasStock()!=null){ boolQuery.filter(QueryBuilders.termQuery("hasStock", searchParam.getHasStock()==1)); } // 按照价格区间 if(!StringUtils.isEmpty(searchParam.getSkuPrice())){ RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("skuPrice"); String[] price = searchParam.getSkuPrice().split("_"); if(price.length == 2){ rangeQuery.gte(price[0]).lte(price[1]); } else if (price.length == 1) { if(searchParam.getSkuPrice().startsWith("_")){ rangeQuery.lte(price[0]); } else if(searchParam.getSkuPrice().endsWith("_")){ rangeQuery.gte(price[0]); } } boolQuery.filter(rangeQuery); } // 把所有条件全部封装 sourceBuilder.query(boolQuery); // 排序 if(!StringUtils.isEmpty(searchParam.getSort())){ String sort = searchParam.getSort(); String[] sortString = sort.split("_"); sourceBuilder.sort(sortString[0],sortString[1].equalsIgnoreCase("asc")?SortOrder.ASC:SortOrder.DESC); } // 分页 if(searchParam.getPageNum()!=null){ sourceBuilder.from((searchParam.getPageNum()-1)*EsConstant.PRODUCT_PAGESIZE); sourceBuilder.size(EsConstant.PRODUCT_PAGESIZE); } // 高亮 if (!StringUtils.isEmpty(searchParam.getKeyword())){ HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("skuTitle"); highlightBuilder.preTags("<b style='color:red'>"); highlightBuilder.postTags("</b>"); sourceBuilder.highlighter(highlightBuilder); } // 品牌聚合 TermsAggregationBuilder brandAgg = AggregationBuilders.terms("brand_agg").field("brandId").size(50); // 品牌聚合的品牌名字子聚合 brandAgg.subAggregation(AggregationBuilders.terms("brand_name_agg").field("brandName").size(1)); // 品牌聚合的品牌图片子聚合 brandAgg.subAggregation(AggregationBuilders.terms("brand_img_agg").field("brandImg").size(1)); // 把品牌聚合放里面 sourceBuilder.aggregation(brandAgg); // 分类聚合 TermsAggregationBuilder catalogAgg = AggregationBuilders.terms("catalog_agg").field("catalogId").size(50); // 分类聚合的品牌名字子聚合 catalogAgg.subAggregation(AggregationBuilders.terms("catalog_name_agg").field("catalogName").size(1)); // 把分类聚合放里面 sourceBuilder.aggregation(catalogAgg); // 属性聚合 NestedAggregationBuilder attrAgg = AggregationBuilders.nested("attrAgg", "attrs"); // 属性ID聚合查询 TermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attr_id_agg").field("attrs.attrId").size(50); // 属性名子聚合 attrIdAgg.subAggregation(AggregationBuilders.terms("attr_name_agg").field("attrs.attrName").size(1)); // 属性值子聚合 attrIdAgg.subAggregation(AggregationBuilders.terms("attr_value_agg").field("attrs.attrValue").size(50)); // 把属性ID聚合查询放进属性内嵌查询 attrAgg.subAggregation(attrIdAgg); // 把属性聚合放里面 sourceBuilder.aggregation(attrAgg); System.out.println(sourceBuilder); return new SearchRequest(new String[]{EsConstant.PRODUCT_INDEX},sourceBuilder); } }
GET alatusmall_product/_search?size=100 { "query": { "bool": { "must": [ { "match": { "skuTitle": { "query": "小米", "operator": "OR", "prefix_length": 0, "max_expansions": 50, "fuzzy_transpositions": true, "lenient": false, "zero_terms_query": "NONE", "auto_generate_synonyms_phrase_query": true, "boost": 1 } } } ], "filter": [ { "term": { "catalogId": { "value": 225, "boost": 1 } } }, { "nested": { "query": { "bool": { "must": [ { "term": { "attrs.attrId": { "value": "13", "boost": 1 } } }, { "terms": { "attrs.attrValue": [ "天玑8300", "麒麟9000s" ], "boost": 1 } } ], "adjust_pure_negative": true, "boost": 1 } }, "path": "attrs", "ignore_unmapped": false, "score_mode": "none", "boost": 1 } }, { "nested": { "query": { "bool": { "must": [ { "term": { "attrs.attrId": { "value": "15", "boost": 1 } } }, { "terms": { "attrs.attrValue": [ "2023" ], "boost": 1 } } ], "adjust_pure_negative": true, "boost": 1 } }, "path": "attrs", "ignore_unmapped": false, "score_mode": "none", "boost": 1 } }, { "term": { "hasStock": { "value": false, "boost": 1 } } }, { "range": { "skuPrice": { "from": "", "to": "6000", "include_lower": true, "include_upper": true, "boost": 1 } } } ], "adjust_pure_negative": true, "boost": 1 } }, "sort": [ { "skuPrice": { "order": "asc" } } ], "aggregations": { "brand_agg": { "terms": { "field": "brandId", "size": 50, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] }, "aggregations": { "brand_name_agg": { "terms": { "field": "brandName", "size": 1, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] } }, "brand_img_agg": { "terms": { "field": "brandImg", "size": 1, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] } } } }, "catalog_agg": { "terms": { "field": "catalogId", "size": 50, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] }, "aggregations": { "catalog_name_agg": { "terms": { "field": "catalogName", "size": 1, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] } } } }, "attrAgg": { "nested": { "path": "attrs" }, "aggregations": { "attr_id_agg": { "terms": { "field": "attrs.attrId", "size": 50, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] }, "aggregations": { "attr_name_agg": { "terms": { "field": "attrs.attrName", "size": 1, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] } }, "attr_value_agg": { "terms": { "field": "attrs.attrValue", "size": 50, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] } } } } } } }, "highlight": { "pre_tags": [ "<b style='color:red'>" ], "post_tags": [ "</b>" ], "fields": { "skuTitle": {} } } }
GET alatusmall_product/_search?size=100
{
"query": {
"bool": {
"must": [
{
"match": {
"skuTitle": {
"query": "小米",
"operator": "OR",
"prefix_length": 0,
"max_expansions": 50,
"fuzzy_transpositions": true,
"lenient": false,
"zero_terms_query": "NONE",
"auto_generate_synonyms_phrase_query": true,
"boost": 1
}
}
}
],
"filter": [
{
"term": {
"catalogId": {
"value": 225,
"boost": 1
}
}
},
{
"nested": {
"query": {
"bool": {
"must": [
{
"term": {
"attrs.attrId": {
"value": "13",
"boost": 1
}
}
},
{
"terms": {
"attrs.attrValue": [
"天玑8300",
"麒麟9000s"
],
"boost": 1
}
}
],
"adjust_pure_negative": true,
"boost": 1
}
},
"path": "attrs",
"ignore_unmapped": false,
"score_mode": "none",
"boost": 1
}
},
{
"nested": {
"query": {
"bool": {
"must": [
{
"term": {
"attrs.attrId": {
"value": "15",
"boost": 1
}
}
},
{
"terms": {
"attrs.attrValue": [
"2023"
],
"boost": 1
}
}
],
"adjust_pure_negative": true,
"boost": 1
}
},
"path": "attrs",
"ignore_unmapped": false,
"score_mode": "none",
"boost": 1
}
},
{
"term": {
"hasStock": {
"value": false,
"boost": 1
}
}
},
{
"range": {
"skuPrice": {
"from": "",
"to": "6000",
"include_lower": true,
"include_upper": true,
"boost": 1
}
}
}
],
"adjust_pure_negative": true,
"boost": 1
}
},
"sort": [
{
"skuPrice": {
"order": "asc"
}
}
],
"aggregations": {
"brand_agg": {
"terms": {
"field": "brandId",
"size": 50,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
},
"aggregations": {
"brand_name_agg": {
"terms": {
"field": "brandName",
"size": 1,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
},
"brand_img_agg": {
"terms": {
"field": "brandImg",
"size": 1,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
}
}
},
"catalog_agg": {
"terms": {
"field": "catalogId",
"size": 50,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
},
"aggregations": {
"catalog_name_agg": {
"terms": {
"field": "catalogName",
"size": 1,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
}
}
},
"attrAgg": {
"nested": {
"path": "attrs"
},
"aggregations": {
"attr_id_agg": {
"terms": {
"field": "attrs.attrId",
"size": 50,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
},
"aggregations": {
"attr_name_agg": {
"terms": {
"field": "attrs.attrName",
"size": 1,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
},
"attr_value_agg": {
"terms": {
"field": "attrs.attrValue",
"size": 50,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
}
}
}
}
}
},
"highlight": {
"pre_tags": [
"<b style='color:red'>"
],
"post_tags": [
"</b>"
],
"fields": {
"skuTitle": {}
}
}
}