商品核心逻辑说明:搜索设计详解

后台-系统设置-扩展变量-手机广告位-内容正文顶部

一、搜索设计

1、设计思路

  商品是高频率搜索功能,数据库查询压力大,所以由elasticsearch进行创建映射,创建索引,进行搜索。。

2、表结构设计

  商品分词表(es_goods_words)

  为商品搜索之前,提供一个模糊查询商品的数量

3、代码示例

  1.创建映射(goodsMapping)EsDeployExecutor#createGoodsMapping方法中新增所需字段

创建商品mapping类型为HashMap

  /**

  *创建商品mapping

  */

  privateMapcreateGoodsMapping(){

  MapgoodsMap=newHashMap();

  //放入商品信息到创建的map中

  goodsMap.put("goodsId",newMyMap().put("type","long").getMap());

  goodsMap.put("goodsName",newMyMap().put("type","text").put("analyzer","ik_max_word").getMap());

  goodsMap.put("thumbnail",newMyMap().put("type","text").getMap());

  goodsMap.put("small",newMyMap().put("type","text").getMap());

  goodsMap.put("buyCount",newMyMap().put("type","integer").getMap());

  goodsMap.put("sellerId",newMyMap().put("type","long").getMap());

  goodsMap.put("sellerName",newMyMap().put("type","text").getMap());

  goodsMap.put("shopCatId",newMyMap().put("type","long").getMap());

  goodsMap.put("shopCatPath",newMyMap().put("type","text").getMap());

  goodsMap.put("commentNum",newMyMap().put("type","integer").getMap());

  goodsMap.put("grade",newMyMap().put("type","double").getMap());

  goodsMap.put("price",newMyMap().put("type","double").getMap());

  goodsMap.put("brand",newMyMap().put("type","long").getMap());

  goodsMap.put("categoryId",newMyMap().put("type","long").getMap());

  goodsMap.put("categoryPath",newMyMap().put("type","text").getMap());

  goodsMap.put("disabled",newMyMap().put("type","integer").getMap());

  goodsMap.put("marketEnable",newMyMap().put("type","integer").getMap());

  goodsMap.put("priority",newMyMap().put("type","integer").getMap());

  goodsMap.put("isAuth",newMyMap().put("type","integer").getMap());

  goodsMap.put("intro",newMyMap().put("type","text").getMap());

  goodsMap.put("selfOperated",newMyMap().put("type","integer").getMap());

  //参数有多种,所以创建多个map

  MapparamPro=newMyMap().put("name",newMyMap().put("type","keyword").getMap()).put("value",newMyMap().put("type","keyword").getMap()).getMap();

  goodsMap.put("params",newMyMap().put("type","nested").put("properties",paramPro).getMap());

  returnnewMyMap().put("properties",goodsMap).getMap();

  }

  2.索引类增加对应属性com.enation.app.javashop.core.goodssearch.model.GoodsIndex这个类中也需要新增对应字段

  @Document(indexName="#{esConfig.indexName}_"+EsSettings.GOODS_INDEX_NAME,type=EsSettings.GOODS_TYPE_NAME)

  publicclassGoodsIndex{

  publicGoodsIndex(){

  }

  @Id

  privateLonggoodsId;

  @Field(type=FieldType.text,analyzer="ik_max_word")

  privateStringgoodsName;

  @Field(type=FieldType.Long)

  privateLongsellerId;

  ....

  }

  3.填充商品信息

  GoodsIndexManagerImpl#getSource方法中添加对应字段,将商品对应字段值信息存储到ES中

把HashMap封装成GoodsIndex类

  /**

  *封装成内存需要格式数据

  *@paramgoods

  */

  protectedGoodsIndexgetSource(Mapgoods){

  GoodsIndexgoodsIndex=newGoodsIndex();

  goodsIndex.setGoodsId(StringUtil.toLong(goods.get("goods_id").toString(),0));

  goodsIndex.setGoodsName(goods.get("goods_name").toString());

  goodsIndex.setThumbnail(goods.get("thumbnail")==null?"":goods.get("thumbnail").toString());

  goodsIndex.setSmall(goods.get("small")==null?"":goods.get("small").toString());

  Doublep=goods.get("price")==null?0d:StringUtil.toDouble(goods.get("price").toString(),0d);

  goodsIndex.setPrice(p);

  DoublediscountPrice=goods.get("discount_price")==null?0d:StringUtil.toDouble(goods.get("discount_price").toString(),0d);

  goodsIndex.setDiscountPrice(discountPrice);

  goodsIndex.setBuyCount(goods.get("buy_count")==null?0:StringUtil.toInt(goods.get("buy_count").toString(),0));

  goodsIndex.setSellerId(StringUtil.toLong(goods.get("seller_id").toString(),0));

  //店铺分组

  goodsIndex.setShopCatId(goods.get("shop_cat_id")==null?0:StringUtil.toLong(goods.get("shop_cat_id").toString(),0));

  goodsIndex.setShopCatPath("");

  if(goodsIndex.getShopCatId()!=0){

  ShopCatDOshopCat=shopCatClient.getModel(goodsIndex.getShopCatId());

  if(shopCat!=null){

  goodsIndex.setShopCatPath(HexUtils.encode(shopCat.getCatPath()));

  }

  }

  goodsIndex.setSellerName(goods.get("seller_name").toString());

  goodsIndex.setCommentNum(goods.get("comment_num")==null?0:StringUtil.toInt(goods.get("comment_num").toString(),0));

  goodsIndex.setGrade(goods.get("grade")==null?100:StringUtil.toDouble(goods.get("grade").toString(),100d));

  goodsIndex.setBrand(goods.get("brand_id")==null?0:StringUtil.toLong(goods.get("brand_id").toString(),0));

  goodsIndex.setCategoryId(goods.get("category_id")==null?0:StringUtil.toLong(goods.get("category_id").toString(),0));

  CategoryDOcat=categoryManager.getModel(Long.valueOf(goods.get("category_id").toString()));

  if(cat!=null){

  goodsIndex.setCategoryPath(HexUtils.encode(cat.getCategoryPath()));

  }

  goodsIndex.setDisabled(StringUtil.toInt(goods.get("disabled").toString(),0));

  goodsIndex.setMarketEnable(StringUtil.toInt(goods.get("market_enable").toString(),0));

  goodsIndex.setIsAuth(StringUtil.toInt(goods.get("is_auth").toString(),0));

  goodsIndex.setIntro(goods.get("intro")==null?"":goods.get("intro").toString());

  goodsIndex.setSelfOperated(goods.get("self_operated")==null?0:StringUtil.toInt(goods.get("self_operated").toString(),0));

  //添加商品优先级维度

  goodsIndex.setPriority(goods.get("priority")==null?1:StringUtil.toInt(goods.get("priority").toString(),1));

  //参数维度,已填写参数

  Listparams=(List)goods.get("params");

  ListparamsList=this.convertParam(params);

  goodsIndex.setParams(paramsList);

  returngoodsIndex;

  }

  4.封装然后存入es

先把HashMap封装成GoodsIndex类,然后在封装到indexQuery类,最后写入elasticsearch

  /**

  *将某个商品加入索引

  *@paramgoods商品数据

  */

  @Override

  @Transactional(value="goodsTransactionManager",propagation=Propagation.REQUIRED,rollbackFor=Exception.class)

  publicvoidaddIndex(Mapgoods){

  StringgoodsName=goods.get("goods_name").toString();

  try{

  //配置文件中定义的索引名字

  StringindexName=esConfig.getIndexName()+"_"+EsSettings.GOODS_INDEX_NAME;

  GoodsIndexgoodsIndex=this.getSource(goods);

  IndexQueryindexQuery=newIndexQuery();

  indexQuery.setIndexName(indexName);

  indexQuery.setType(EsSettings.GOODS_TYPE_NAME);

  indexQuery.setId(goodsIndex.getGoodsId().toString());

  indexQuery.setObject(goodsIndex);

  //审核通过且没有下架且没有删除

  booleanflag=goodsIndex.getDisabled()==1&&goodsIndex.getMarketEnable()==1&&goodsIndex.getIsAuth()==1;

  if(flag){

  ListwordsList=toWordsList(goodsName);

  //分词入库

  this.wordsToDb(wordsList);

  }

  elasticsearchOperations.index(indexQuery);

  }catch(Exceptione){

  e.printStackTrace();

  logger.error("为商品["+goodsName+"]生成索引异常",e);

  debugger.log("为商品["+goodsName+"]生成索引异常",StringUtil.getStackTrace(e));

  thrownewRuntimeException("为商品["+goodsName+"]生成索引异常",e);

  }

  }

  5.商品搜索参数

如果新增字段不做为搜索参数可忽略此步骤

  GoodsSearchManagerImpl#createQuery方法中,添加对应字段的搜索表达式

  /**

  *构建查询条件

  *@throwsException

  */

  protectedSearchRequestBuildercreateQuery(GoodsSearchDTOgoodsSearch)throwsException{

  Stringkeyword=goodsSearch.getKeyword();

  Longcat=goodsSearch.getCategory();

  Longbrand=goodsSearch.getBrand();

  Stringprice=goodsSearch.getPrice();

  LongsellerId=goodsSearch.getSellerId();

  LongshopCatId=goodsSearch.getShopCatId();

  SearchRequestBuildersearchRequestBuilder=elasticsearchTemplate.getClient().prepareSearch(esConfig.getIndexName()+"_"+EsSettings.GOODS_INDEX_NAME);

  BoolQueryBuilderboolQueryBuilder=QueryBuilders.boolQuery();

  //关键字检索

  if(!StringUtil.isEmpty(keyword)){

  QueryStringQueryBuilderqueryString=newQueryStringQueryBuilder(keyword).field("goodsName");

  queryString.defaultOperator(Operator.AND);

  //按照关键字检索关键字无需按照最细粒度分词updatebyliuyulei2019-12-12

  queryString.analyzer("ik_smart");

  queryString.useDisMax(false);

  boolQueryBuilder.must(queryString);

  }

  //品牌搜素

  if(brand!=null){

  boolQueryBuilder.must(QueryBuilders.termQuery("brand",brand));

  }

  //分类检索

  if(cat!=null){

  CategoryDOcategory=categoryManager.getModel(cat);

  if(category==null){

  thrownewServiceException("","该分类不存在");

  }

  boolQueryBuilder.must(QueryBuilders.wildcardQuery("categoryPath",HexUtils.encode(category.getCategoryPath())+"*"));

  }

  //卖家搜索

  if(sellerId!=null){

  boolQueryBuilder.must(QueryBuilders.termQuery("sellerId",sellerId));

  }

  //卖家分组搜索

  if(shopCatId!=null){

  ShopCatDOshopCat=shopCatClient.getModel(shopCatId);

  if(shopCat==null){

  thrownewServiceException("","该分组不存在");

  }

  boolQueryBuilder.must(QueryBuilders.wildcardQuery("shopCatPath",HexUtils.encode(shopCat.getCatPath())+"*"));

  }

  //参数检索

  Stringprop=goodsSearch.getProp();

  if(!StringUtil.isEmpty(prop)){

  String[]propArray=prop.split(Separator.SEPARATOR_PROP);

  for(Stringp:propArray){

  String[]onpropAr=p.split(Separator.SEPARATOR_PROP_VLAUE);

  Stringname=onpropAr[0];

  Stringvalue=onpropAr[1];

  boolQueryBuilder.must(QueryBuilders.nestedQuery("params",QueryBuilders.termQuery("params.name",name),ScoreMode.None));

  boolQueryBuilder.must(QueryBuilders.nestedQuery("params",QueryBuilders.termQuery("params.value",value),ScoreMode.None));

  }

  }

  //价格搜索

  if(!StringUtil.isEmpty(price)){

  String[]pricear=price.split(Separator.SEPARATOR_PROP_VLAUE);

  doublemin=StringUtil.toDouble(pricear[0],0.0);

  doublemax=Integer.MAX_VALUE;

  if(pricear.length==2){

  max=StringUtil.toDouble(pricear[1],Double.MAX_VALUE);

  }

  boolQueryBuilder.must(QueryBuilders.rangeQuery("price").from(min).to(max).includeLower(true).includeUpper(true));

  }

  //删除的商品不显示

  boolQueryBuilder.must(QueryBuilders.termQuery("disabled","1"));

  //未上架的商品不显示

  boolQueryBuilder.must(QueryBuilders.termQuery("marketEnable","1"));

  //待审核和审核不通过的商品不显示

  boolQueryBuilder.must(QueryBuilders.termQuery("isAuth","1"));

  searchRequestBuilder.setQuery(boolQueryBuilder);

  //排序

  StringsortField=goodsSearch.getSort();

  StringsortId="priority";

  SortOrdersort=SortOrder.DESC;

  if(!StringUtil.isEmpty(sortField)){

  MapsortMap=SortContainer.getSort(sortField);

  sortId=sortMap.get("id");

  //如果是默认排序--默认排序根据商品优先级排序addbyliuyulei_2019-07-01

  if("def".equals(sortId)){

  sortId="priority";

  }

  if("buynum".equals(sortId)){

  sortId="buyCount";

  }

  if("grade".equals(sortId)){

  sortId="commentNum";

  }

  if("desc".equals(sortMap.get("def_sort"))){

  sort=SortOrder.DESC;

  }else{

  sort=SortOrder.ASC;

  }

  }

  searchRequestBuilder.addSort(sortId,sort);

  //好平率

  if("commentNum".equals(sortId)){

  searchRequestBuilder.addSort("buyCount",sort);

  //boolQueryBuilder.must(QueryBuilders.rangeQuery("buyCount").from(1).includeLower(true));

  }

  //如果不是默认排序则在原有搜索结果基础上加上商品优先级排序addbyliuyulei2019-07-01

  if(!"priority".equals(sortId)){

  //商品优先级

  searchRequestBuilder.addSort("priority",SortOrder.DESC);

  }

  returnsearchRequestBuilder;

  }

ES搜索新增字段之后,需要执行部署程序重新初始化ES,然后管理端手动点击生成索引,否则搜索不到新增字段数据

  以上就是关于搜索设计的全部内容,想了解更多详情,可以持续关注易族智汇javashop

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

后台-系统设置-扩展变量-手机广告位-内容正文底部
留言与评论(共有 0 条评论)
   
验证码: