elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuMap.class);
该实例通过nativeSearchQueryBuilder.withQuery()方法构建了一个通过关键字查询,参数1是前端传递的值,参数2是指索引库中哪一个字段为关键字
nativeSearchQueryBuilder.withQuery(QueryBuilders.queryStringQuery(keywords).field("name"));
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuCategory").field("categoryName"));
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuCategory").field("categoryName"));
AggregatedPage<SkuMap> aggregatedPage = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuMap.class);
/**
* 获取分组的数据
* getAggregations() 获取的是集合可以根据多个域分组
* get("skuCategory") 获取指定域的集合数据 【手机,家用电器,手机配件】
*/
StringTerms skuCategory = aggregatedPage.getAggregations().get("skuCategory");
List<String> categoryList = new ArrayList<>();
for (StringTerms.Bucket bucket : skuCategory.getBuckets()) {
//获取其中一个分类的名称
String categoryName = bucket.getKeyAsString();
categoryList.add(categoryName);
}
@GetMapping
public Map search(@RequestParam(required = false) Map searchMap){
return skuInfoService.search(searchMap);
}
public Map search(Map<String, String> searchMap) {
/**
* elasticsearchTemplate; //执行索引库操作
* NativeSearchQueryBuilder 搜索条件构建对象 用于封装各类搜索条件
*/
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
if (searchMap != null && searchMap.size() > 0){
//获取关键字的值
String keywords = searchMap.get("keywords");
if (!StringUtils.isEmpty(keywords)){
//name es库中的name
nativeSearchQueryBuilder.withQuery(QueryBuilders.queryStringQuery(keywords).field("name"));
}
}
/**
* 分组查询分类集合
* addAggregation 添加一个聚合操作 比如mysql中的group by count 等函数
* field 表示根据哪个域进行分组 es分类名称 categoryName
* terms 取别名
*/
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuCategory").field("categoryName"));
AggregatedPage<SkuMap> aggregatedPage = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuMap.class);
/**
* queryForPage 1.搜索条件封装 2.返回数据的封装
*/
AggregatedPage<SkuMap> page = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuMap.class);
/**
* 获取分组的数据
* getAggregations() 获取的是集合可以根据多个域分组
* get("skuCategory") 获取指定域的集合数据 【手机,家用电器,手机配件】
*/
StringTerms skuCategory = aggregatedPage.getAggregations().get("skuCategory");
List<String> categoryList = new ArrayList<>();
for (StringTerms.Bucket bucket : skuCategory.getBuckets()) {
//获取其中一个分类的名称
String categoryName = bucket.getKeyAsString();
categoryList.add(categoryName);
}
//分页参数->总记录数
long totalElements = page.getTotalElements();
//分页参数->总页数
int totalPages = page.getTotalPages();
//获取结果集
List<SkuMap> content = page.getContent();
//封装返回map集合
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("rows", content);
resultMap.put("total", totalElements);
resultMap.put("totalPages", totalPages);
//分类集合
resultMap.put("categoryList",categoryList);
return resultMap;
}
/**
* 数据搜索
* @param searchMap
* @return
*/
@Override
public Map search(Map<String, String> searchMap) {
//搜索条件封装
NativeSearchQueryBuilder nativeSearchQueryBuilder = searchQueryBuilder(searchMap);
//集合搜索
Map<String, Object> resultMap = searchList(nativeSearchQueryBuilder);
//分类分组查询
List<String> categoryList = searchCateList(nativeSearchQueryBuilder);
resultMap.put("categoryList",categoryList);
return resultMap;
}
/**
* 搜索条件封装
* @param searchMap
* @return
*/
public NativeSearchQueryBuilder searchQueryBuilder(Map<String, String> searchMap) {
/**
* elasticsearchTemplate; //执行索引库操作
* NativeSearchQueryBuilder 搜索条件构建对象 用于封装各类搜索条件
*/
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
if (searchMap != null && searchMap.size() > 0){
//获取关键字的值
String keywords = searchMap.get("keywords");
if (!StringUtils.isEmpty(keywords)){
//name es库中的name
nativeSearchQueryBuilder.withQuery(QueryBuilders.queryStringQuery(keywords).field("name"));
}
}
return nativeSearchQueryBuilder;
}
/**
* 集合搜索
* @param nativeSearchQueryBuilder
* @return
*/
public Map<String, Object> searchList(NativeSearchQueryBuilder nativeSearchQueryBuilder) {
/**
* queryForPage 1.搜索条件封装 2.返回数据的封装
*/
AggregatedPage<SkuMap> page = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuMap.class);
//分页参数->总记录数
long totalElements = page.getTotalElements();
//分页参数->总页数
int totalPages = page.getTotalPages();
//获取结果集
List<SkuMap> content = page.getContent();
//封装返回map集合
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("rows", content);
resultMap.put("total", totalElements);
resultMap.put("totalPages", totalPages);
return resultMap;
}
/**
* 分类分组数据查询
* @param nativeSearchQueryBuilder
* @return
*/
public List<String> searchCateList(NativeSearchQueryBuilder nativeSearchQueryBuilder) {
/**
* 分组查询分类集合
* addAggregation 添加一个聚合操作 比如mysql中的group by count 等函数
* field 表示根据哪个域进行分组 es分类名称 categoryName
* terms 取别名
*/
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuCategory").field("categoryName"));
AggregatedPage<SkuMap> aggregatedPage = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuMap.class);
/**
* 获取分组的数据
* getAggregations() 获取的是集合可以根据多个域分组
* get("skuCategory") 获取指定域的集合数据 【手机,家用电器,手机配件】
*/
StringTerms skuCategory = aggregatedPage.getAggregations().get("skuCategory");
List<String> categoryList = new ArrayList<>();
for (StringTerms.Bucket bucket : skuCategory.getBuckets()) {
//获取其中一个分类的名称
String categoryName = bucket.getKeyAsString();
categoryList.add(categoryName);
}
return categoryList;
}
public Map search(Map<String, String> searchMap) {
//搜索条件封装
NativeSearchQueryBuilder nativeSearchQueryBuilder = searchQueryBuilder(searchMap);
//集合搜索 并添加高亮
Map<String, Object> resultMap = searchList(nativeSearchQueryBuilder);
//当用户选择了分类 将分类作为搜索条件,则不需要对分类进行分组搜索,该值只用作于显示分类搜索的条件
//分类分组查询
if (searchMap == null || StringUtils.isEmpty(searchMap.get("category"))){
List<String> categoryList = searchCateList(nativeSearchQueryBuilder);
resultMap.put("categoryList", categoryList);
}
//当用户选择了品牌 将品牌作为搜索条件,则不需要对品牌进行分组搜索,该值只用作于显示品牌搜索的条件
//查询品牌集合
if (searchMap == null || StringUtils.isEmpty(searchMap.get("brand"))){
List<String> brandList = searchBrandList(nativeSearchQueryBuilder);
resultMap.put("brandList", brandList);
}
//获取规格数据
Map<String, Set<String>> specList = searchSpecList(nativeSearchQueryBuilder);
resultMap.put("specList", specList);
return resultMap;
}
/**
* 搜索条件封装
* @param searchMap
* @return
*/
public NativeSearchQueryBuilder searchQueryBuilder(Map<String, String> searchMap) {
/**
* elasticsearchTemplate; //执行索引库操作
* NativeSearchQueryBuilder 搜索条件构建对象 用于封装各类搜索条件
* BoolQueryBuilder 组合条件 多条件过滤 must must—not should 组合方式
*/
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
if (searchMap != null && searchMap.size() > 0){
//获取关键字的值
String keywords = searchMap.get("keywords");
if (!StringUtils.isEmpty(keywords)){
//name es库中的name
//nativeSearchQueryBuilder.withQuery(QueryBuilders.queryStringQuery(keywords).field("name"));
boolQueryBuilder.must(QueryBuilders.queryStringQuery(keywords).field("name"));
}
//分类 category
if (!StringUtils.isEmpty(searchMap.get("category"))){
boolQueryBuilder.must(QueryBuilders.termQuery("categoryName", searchMap.get("category")));
}
//品牌 brand
if (!StringUtils.isEmpty(searchMap.get("brand"))){
boolQueryBuilder.must(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
}
//规格
for (Map.Entry<String, String> entry : searchMap.entrySet()) {
String key = entry.getKey();
//如果key是以spec_开始,则表示按规格条件查询
//spec_网络=4G
//specMap.网络.keyword //索引库的列
if (key.startsWith("spec_")){
String value = entry.getValue(); //搜索的条件
boolQueryBuilder.must(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", value));
}
}
//价格 0-500元 500元以上 去掉中文和元获取0和500
String price = searchMap.get("price");
if (!StringUtils.isEmpty(price)){
//截取分割
price = price.replace("元","").replace("以上","");
String[] prices = price.split("-");
if (prices != null && prices.length > 0){
//rangeQuery 范围搜索 gt >
boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gt(Integer.parseInt(prices[0])));
if (prices.length == 2){
boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lte(Integer.parseInt(prices[1])));
}
}
}
/**
* 排序
* sortField 要排序的域
* sortRule 要排序的规则
*/
String sortField = searchMap.get("sortField");
String sortRule = searchMap.get("sortRule");
if (!StringUtils.isEmpty(sortField) && !StringUtils.isEmpty(sortRule)){
nativeSearchQueryBuilder.withSort(
new FieldSortBuilder(sortField) // 要排序的域
.order(SortOrder.valueOf(sortRule))); // 要排序的规则desc或asc
}
}
/**
* 分页
* 不传分页参数默认第一页
* 不传size默认就3条
*/
Integer[] page = coverterPage(searchMap); //页数
nativeSearchQueryBuilder.withPageable(PageRequest.of(page[0] -1,page[1]));
//boolQueryBuilder 填冲给nativeSearchQueryBuilder
nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
return nativeSearchQueryBuilder;
}
/**
* 集合搜索
* @param nativeSearchQueryBuilder
* @return
*/
public Map<String, Object> searchList(NativeSearchQueryBuilder nativeSearchQueryBuilder) {
/**
* queryForPage 1.搜索条件封装 2.返回数据的封装
* 不加高亮方法
*
AggregatedPage page = elasticsearchTemplate.queryForPage(
nativeSearchQueryBuilder.build(),
SkuMap.class);
*/
/**
* 添加高亮
*/
HighlightBuilder.Field field = new HighlightBuilder.Field("name"); //指定高亮域(按名称);
//添加前缀、后缀、碎片长度(name的长度限制)
field.preTags("");//前缀 高亮显示红色
field.postTags(""); //后缀
field.fragmentSize(100);//关键词数据的长度
nativeSearchQueryBuilder.withHighlightFields(field);
AggregatedPage<SkuMap> page = elasticsearchTemplate.queryForPage(
nativeSearchQueryBuilder.build(), //条件封装
SkuMap.class, //要转换的类型
// SearchResultMapper); 执行结果集之后封装的对象中,自身是个借口
new SearchResultMapper() {
@Override
public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
//存储所有转换后的高亮数据对象
List<T> list = new ArrayList<>();
//searchResponse.getHits() 获取所有数据
for (SearchHit hit : searchResponse.getHits()) {
//获取非高亮数据并转换成对象
SkuMap skuMap = JSON.parseObject(hit.getSourceAsString(),SkuMap.class);
//获取高亮数据
HighlightField name = hit.getHighlightFields().get("name");
//getFragments 碎片长度不等于空
if (name != null && name.getFragments() != null){
//读取高亮数据
Text[] fragments = name.getFragments();
StringBuffer stringBuffer = new StringBuffer();
for (Text text : fragments) {
stringBuffer.append(text.toString());
}
//将非高亮数据指定的域替换成高亮数据
skuMap.setName(stringBuffer.toString());
}
list.add((T) skuMap);
}
/**
* 返回AggregatedPage接口的实现类 AggregatedPageImpl
* ① 返回的数据
* ② 分页对象信息
* ③ 搜索的记录条数
*/
return new AggregatedPageImpl<T>(list, pageable, searchResponse.getHits().getTotalHits());
}
});
//分页参数->总记录数
long totalElements = page.getTotalElements();
//分页参数->总页数
int totalPages = page.getTotalPages();
//获取结果集
List<SkuMap> content = page.getContent();
//封装返回map集合
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("rows", content);
resultMap.put("total", totalElements);
resultMap.put("totalPages", totalPages);
return resultMap;
}
/**
* 分类分组数据查询
* @param nativeSearchQueryBuilder
* @return
*/
public List<String> searchCateList(NativeSearchQueryBuilder nativeSearchQueryBuilder) {
/**
* 分组查询分类集合
* addAggregation 添加一个聚合操作 比如mysql中的group by count 等函数
* field 表示根据哪个域进行分组 es分类名称 categoryName
* terms 取别名
*/
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuCategory").field("categoryName"));
AggregatedPage<SkuMap> aggregatedPage = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuMap.class);
/**
* 获取分组的数据
* getAggregations() 获取的是集合可以根据多个域分组
* get("skuCategory") 获取指定域的集合数据 【手机,家用电器,手机配件】
*/
StringTerms skuCategory = aggregatedPage.getAggregations().get("skuCategory");
List<String> categoryList = new ArrayList<>();
for (StringTerms.Bucket bucket : skuCategory.getBuckets()) {
//获取其中一个分类的名称
String categoryName = bucket.getKeyAsString();
categoryList.add(categoryName);
}
return categoryList;
}
/**
* 品牌分组数据查询
* @param nativeSearchQueryBuilder
* @return
*/
public List<String> searchBrandList(NativeSearchQueryBuilder nativeSearchQueryBuilder) {
/**
* 品牌分组数据查询
* addAggregation 添加一个聚合操作 比如mysql中的group by count 等函数
* field 表示根据哪个域进行分组 es分类名称 categoryName
* terms 取别名
*/
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuBrand").field("brandName"));
AggregatedPage<SkuMap> aggregatedPage = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuMap.class);
/**
* 获取分组的数据
* getAggregations() 获取的是集合可以根据多个域分组
* get("skuCategory") 获取指定域的集合数据 【TCL.华为,小米】
*/
StringTerms stringTerms = aggregatedPage.getAggregations().get("skuBrand");
List<String> brandList = new ArrayList<>();
for (StringTerms.Bucket bucket : stringTerms.getBuckets()) {
//获取其中一个分类的名称
String brandName = bucket.getKeyAsString();
brandList.add(brandName);
}
return brandList;
}
/**
* 规格分组数据查询
* @param nativeSearchQueryBuilder
* @return
*/
public Map<String, Set<String>> searchSpecList(NativeSearchQueryBuilder nativeSearchQueryBuilder) {
/**
* spec.keyword keyword不分词
* size 可以不设置,默认查询数量10
*/
//nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuSpec").field("spec.keyword"));
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuSpec").field("spec.keyword").size(10000));
AggregatedPage<SkuMap> aggregatedPage = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuMap.class);
/**
* 获取分组的数据
* getAggregations() 获取的是集合可以根据多个域分组
* get("skuSpec") 获取指定域的集合数据 [{"尺寸":"20寸","音响效果":"立体声"},{"音响效果":"小影院","尺寸":"21寸"}]
*/
StringTerms stringTerms = aggregatedPage.getAggregations().get("skuSpec");
List<String> specList = new ArrayList<>();
for (StringTerms.Bucket bucket : stringTerms.getBuckets()) {
//获取其中一个规格的名称
String specName = bucket.getKeyAsString();
specList.add(specName);
}
Map<String, Set<String>> allSpec = putSpecAll(specList);
return allSpec;
}
/**
* 规格汇总合并
* @param specList
* @return
*/
public Map<String, Set<String>> putSpecAll(List<String> specList) {
//将List中的json字符转转换成map并将每个map合并成一个map>
//合并后的map对象
Map<String, Set<String>> allSpec = new HashMap<>();
for (String spec : specList) {
//转map
Map <String, String> specMap = JSON.parseObject(spec, Map.class);
//合并到allspec中
for (Map.Entry<String, String> entry : specMap.entrySet()) {
String key = entry.getKey(); //规格的名称 尺寸
String value = entry.getValue(); //规格的值
//先从allSpec中获取一次当前规格对应的set集合数据
Set<String> strings = allSpec.get(key);
if (strings == null) {
//如果没有改规格
strings = new HashSet<>();
}
strings.add(value);
allSpec.put(key,strings);
}
}
return allSpec;
}
/**
* 前端分页参数
* @param searchMap
* @return
*/
public Integer[] coverterPage(Map<String, String> searchMap) {
Integer[] param = new Integer[2];
if (searchMap != null) {
String pageNum = searchMap.get("pageNum");
String size = searchMap.get("size");
try {
param[0] = Integer.parseInt(pageNum);
param[1] = Integer.parseInt(size);
return param;
} catch (NumberFormatException e) {
}
}
param[0] = 1;
param[1] = 3;
return param;
}
/**
* 数据搜索
* @param searchMap
* @return
*/
@Override
public Map search(Map<String, String> searchMap) {
//搜索条件封装
NativeSearchQueryBuilder nativeSearchQueryBuilder = searchQueryBuilder(searchMap);
//集合搜索 并添加高亮
Map<String, Object> resultMap = searchList(nativeSearchQueryBuilder);
Map<String, Object> groupList = searchGroupList(nativeSearchQueryBuilder, searchMap);
resultMap.putAll(groupList);
return resultMap;
}
/**
* 封装 分类 品牌 规格
* @param nativeSearchQueryBuilder
* @return
*/
public Map<String, Object> searchGroupList(NativeSearchQueryBuilder nativeSearchQueryBuilder,Map<String, String> searchMap) {
//分类
if (searchMap == null || StringUtils.isEmpty(searchMap.get("category"))){
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuCategory").field("categoryName"));
}
//品牌
if (searchMap == null || StringUtils.isEmpty(searchMap.get("brand"))){
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuBrand").field("brandName"));
}
//规格
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuSpec").field("spec.keyword").size(10000));
AggregatedPage<SkuMap> aggregatedPage = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuMap.class);
//返回map 存储所有返回的数据
Map<String, Object> groupMapResult = new HashMap<>();
if (searchMap == null || StringUtils.isEmpty(searchMap.get("category"))){
StringTerms categoryTerms = aggregatedPage.getAggregations().get("skuCategory");
List<String> categoryList = groupTerms(categoryTerms);
groupMapResult.put("categoryList", categoryList);
}
if (searchMap == null || StringUtils.isEmpty(searchMap.get("brand"))){
StringTerms brandTerms = aggregatedPage.getAggregations().get("skuBrand");
List<String> brandList = groupTerms(brandTerms);
groupMapResult.put("brandList", brandList);
}
//规格
StringTerms skuSpecTerms = aggregatedPage.getAggregations().get("skuSpec");
List<String> SpecList = groupTerms(skuSpecTerms);
Map<String, Set<String>> stringSetMap = putSpecAll(SpecList);
//合并返回
groupMapResult.put("specList", stringSetMap);
return groupMapResult;
}
/**
* 返回分组结合数据
* @param stringTerms
* @return
*/
public List<String> groupTerms(StringTerms stringTerms){
List<String> groupTermsList = new ArrayList<>();
for (StringTerms.Bucket bucket : stringTerms.getBuckets()) {
String fieldName = bucket.getKeyAsString();
groupTermsList.add(fieldName);
}
return groupTermsList;
}
http://127.0.0.1:10086/search?brand=华为?category=笔记本.....
demo连接地址
https://e.coding.net/mzjmc/elasticsearch/elasticsearch.git