1构建搜索条件(NativeSearchQueryBuilder)
关键的类
//构建搜索条件 用于封装各种搜索条件
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
//过滤搜索// 模糊查询
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
//高亮搜索
HighlightBuilder.Field filed = new HighlightBuilder.Field("name");//高亮的域
//高亮数据 和 非高亮数据 是不在一块的 替换 。。
/**
* 执行搜索相应结果给我
* >1 搜索条件封装对象
* >2 搜索的结果集(集合转化的对象)需要转化的类型
* >3 AggregatedPage<SkuInfo> 返回结果集的封装
*/
//高亮代码思路
/**
* 搜索条件封装
*/
private NativeSearchQueryBuilder buildBaseQuery(Map<String, String> searchMap) {
//构建搜索条件 用于封装各种搜索条件
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
//过滤搜索// 模糊查询
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
//根据关键词搜索
if (searchMap != null & searchMap.size() > 0) {
//根据关键词搜索
String keywords = searchMap.get("keywords");
//如果关键词不为空则搜索关键词数据
if (!StringUtils.isEmpty(keywords)) { //指定域名 name
boolQueryBuilder.must(QueryBuilders.queryStringQuery(keywords).field("name"));
}
//搜索了分类 >category
if (!StringUtils.isEmpty(searchMap.get("category"))) { //指定域名 name
boolQueryBuilder.must(QueryBuilders.termQuery("categoryName", searchMap.get("category")));
}
//输入了品牌 >brand
if (!StringUtils.isEmpty(searchMap.get("brand"))) { //指定域名 name
boolQueryBuilder.must(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
}
//规格过滤 条件搜索
for (Map.Entry<String, String> entry : searchMap.entrySet()) {
//判断searchMap中是否存在spec_开头的
String key = entry.getKey();
if (key.startsWith("spec_")) {
String value = entry.getValue();
boolQueryBuilder.must(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", value));
}
}
String price = searchMap.get("price");
if (!StringUtils.isEmpty(price)) {
price = price.replace("元", "").replace("以上", "");
//用-进行分割
String[] prices = price.split("-");
if (prices != null && prices.length > 0) { //gt > 当有2个时候lte<
boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gt(Integer.parseInt(prices[0])));
if (prices.length == 2) {
boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lte(Integer.parseInt(prices[1])));
}
}
}
//排序 实现
String sortFiled = searchMap.get("sortFiled");//指定排序 的域
String sortRule = searchMap.get("sortRule"); //指定排序的规则
if (!StringUtils.isEmpty(sortFiled) && !StringUtils.isEmpty(sortRule)) {
nativeSearchQueryBuilder.withSort(new FieldSortBuilder(sortFiled) //指定域
.order(SortOrder.valueOf(sortRule))); //排序规则
}
}
//分页
Integer pageNumber = converterPage(searchMap);
Integer pageSize = 30; //每页显示的数量
nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNumber, pageSize));
nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
return nativeSearchQueryBuilder;
}
2.数据结果封装
/**
* 数据结果集封装
*
* @param nativeSearchQueryBuilder
* @return
*/
private HashMap<String, Object> searchList(NativeSearchQueryBuilder nativeSearchQueryBuilder) {
//高亮搜索
HighlightBuilder.Field filed = new HighlightBuilder.Field("name");//高亮的域
//前缀
//<em style="color":red;">
filed.preTags("<em style='color:red;'>"); //转义符
//后缀 </em>
filed.postTags("</em>");
//碎片长度 关键词数据的长度
filed.fragmentSize(100); //100字符截取
nativeSearchQueryBuilder.withHighlightFields(filed);
//高亮数据 和 非高亮数据 是不在一块的 替换 。。
/**
* 执行搜索相应结果给我
* >1 搜索条件封装对象
* >2 搜索的结果集(集合转化的对象)需要转化的类型
* >3 AggregatedPage<SkuInfo> 返回结果集的封装
*/
//AggregatedPage<SkuInfo> page = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuInfo.class);
AggregatedPage<SkuInfo> page = elasticsearchTemplate.
queryForPage(
nativeSearchQueryBuilder.build(), //搜索条件封装
SkuInfo.class,//数据集合要转化的类型的字节码
// SearchResultMapper); //执行搜索后,将数据结果封装到该对象中
new SearchResultMapper() {
@Override
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {
//储存所以转换后的高亮对象
List<T> list = new ArrayList<>();
//执行查询,获取所有数据->结果集[非高亮数据][高亮数据]
for (SearchHit hit : response.getHits()) {
//分析结果集数据,获取非高亮数据
SkuInfo skuInfo = JSON.parseObject(hit.getSourceAsString(), SkuInfo.class);
//分析结果集 获取高亮数据>只有某个域的高亮数据
HighlightField highField = hit.getHighlightFields().get("name");
if (highField != null && highField.getFragments() != null) {
//高亮数据读取出来
StringBuffer buffer = new StringBuffer();
Text[] fragments = highField.getFragments();
for (Text fragment : fragments) {
buffer.append(fragment.toString());
}
//非高亮数据中 指定的域替换成高亮数据
skuInfo.setName(buffer.toString());
}
//将高亮数据存入集合
list.add((T) skuInfo);
}
return new AggregatedPageImpl<T>(list, pageable, response.getHits().getTotalHits());
}
});
//分页参数总记录数
long totalElements = page.getTotalElements();
//总页数
int totalPages = page.getTotalPages();
//获取数据返回集合
List<SkuInfo> contents = page.getContent();
//将数据添加到map 返回集合
HashMap<String, Object> map = new HashMap<>();
//分页数据
map.put("rows", contents);
map.put("total", totalElements);
map.put("totalPages", totalPages);
//获取搜索封装信息
NativeSearchQuery query=nativeSearchQueryBuilder.build();
Pageable pageable = query.getPageable();//获取分页信息
int pageSize=pageable.getPageSize();
int pageNumber = pageable.getPageNumber();//获取页码
map.put("pageSize", pageSize);
map.put("pageNumber", pageNumber);
return map;
}
3 分组进行模糊查询
/**
* 分组查询分类集合
* 添加 一个聚合操作
* 1 取别名 ------------- 分类分组查询
* 2根据那个域分组
*/
private Map<String, Object> searchGroupList(NativeSearchQueryBuilder nativeSearchQueryBuilder, Map<String, String> searchMap) {
/**
* 分组查询分类集合
* .addAggregation :添加 一个聚合操作
* 1) 取别名
* 2) 表示根据某个域进行分组查询
*/
//定义一个Map存储所有的分组数据
Map<String, Object> groupMapResult = new HashMap<>();
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"));
AggregatedPage<SkuInfo> aggregatedPage = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuInfo.class);
if (searchMap == null || StringUtils.isEmpty(searchMap.get("category"))) {
StringTerms categoryTerms = aggregatedPage.getAggregations().get("skuCategory");
List<String> categoryList = getGroupList(categoryTerms);
groupMapResult.put("categoryList", categoryList);
}
if (searchMap == null || StringUtils.isEmpty(searchMap.get("brand"))) {
StringTerms brandTerms = aggregatedPage.getAggregations().get("skuBrand");
List<String> brandList = getGroupList(brandTerms);
groupMapResult.put("brandList", brandList);
}
StringTerms specTerms = aggregatedPage.getAggregations().get("skuSpec");
//获取规格分组的集合数据--->实现合并 操作
List<String> specList = getGroupList(specTerms);
Map<String, Set<String>> specMap = putAllSpec(specList);
groupMapResult.put("specList", specMap);
return groupMapResult;
}
获取分组集合数据
/**
* 获取分组集合数据
*
* @param stringTerms
* @return
*/
public List<String> getGroupList(StringTerms stringTerms) {
List<String> groupList = new ArrayList<>();
for (StringTerms.Bucket bucket : stringTerms.getBuckets()) {
String filedName = bucket.getKeyAsString();
groupList.add(filedName);
}
return groupList;
}
4 最终代码
@Override
public Map SearchMap(Map<String, String> searchMap) {
/**
* 搜索条件封装
*/
NativeSearchQueryBuilder nativeSearchQueryBuilder = buildBaseQuery(searchMap);
HashMap<String, Object> map = searchList(nativeSearchQueryBuilder);
Map<String, Object> groupMap = searchGroupList(nativeSearchQueryBuilder, searchMap);
map.putAll(groupMap);
return map;
}
5:商品信息导入索引库
@Override
public void importData() {
//调用Feign读取 Sku
Result<List<Sku>> skuResult = skuFeign.findByStatus("1");
//将List<Sku> 转成List<SkuInfo>
List<SkuInfo> skuInfoList = JSON.parseArray(JSON.toJSONString(skuResult.getData()), SkuInfo.class);
for (SkuInfo skuInfo : skuInfoList) {
//skuInfo.getSpec()Map字符串 转成Map
Map<String, Object> maps = JSON.parseObject(skuInfo.getSpec(), Map.class);
//如果要生成动态的域,只需要将该域存入一个Map<String,Object>对象即可,
// 该Map<String,Object>的key会自动生成一个域,域的名字为该Map的key
//当前Map<String,Object>后面的Object的值会作为当前Sku对象该域的(key)对应的值
skuInfo.setSpecMap(maps);
}
//调用Dao实现数据批量导入
skuEsMapper.saveAll(skuInfoList);
}
6 总结:
封装重复代码
目标
思路
代码
学会分析代码.