项目总结|项目中如何应用Elasticsearch的 - Go语言中文社区

项目总结|项目中如何应用Elasticsearch的


前言

在项目中涉及到商品搜索的模块,通过学习ES的知识,便尝试着将ES应用到了项目当中,这篇博客主要叙述我在项目中是如何使用ES的。由于我们一起买的阿里云服务器已经到期了,这里就不演示了。以后工作一定要买台好的服务器

如果大家也想安装一下ES和Kibana,可以按照我之前的博客来搭建
传送门<----点这

ES中数据的模型

想要从ES中查数据,首先需要把数据存入到ES当中,当时和同学商量着直接在Kibana中批量导入这些数据,但是想想,这样太麻烦了,后来想到同学写的后台管理有商品上架的功能,然后就从这里入手了。

模型的设计

来看下我们设计的模型:

@Data
public class SkuEsModel {
	//具体商品的id
    private Long skuId;
	//某类商品的id 
    private Long spuId;
    //销售商品的标题
    private String skuTitle;
    //销售商品的价格
    private BigDecimal skuPrice;
    //销售商品的图片
    private String skuImg;
    //商品的销量
    private Long saleCount;
    //商品是否有库存
    private Boolean hasStock;
    //商品的评分
    private Long hotScore;
    //商品所属品牌的id
    private Long brandId;
    //商品所属分类的id
    private Long catalogId;
    //商品所属品牌的名字
    private String brandName;
    //商品所属品牌的图片
    private String brandImg;
    //商品所属分类的名字
    private String catalogName;
    //商品所对应的属性
    private List<Attrs> attrs;
    @Data
    public static class Attrs {
    	//属性id
        private Long attrId;
        //属性的名字
        private String attrName;
        //属性值
        private String attrValue;
    }
}

为什么这样设计

首先先聊聊商城都有什么业务用到了es:

  • 通过商城首页的三级列表的三级目录进入到搜索页面
  • 通过商城首页的搜索框输入要搜索商品的名字,通过查es返回数据

在三级目录点击进入的话会传一个分类id的参数,所以模型中应该有分类id提供搜索,然后就是通过搜索框输入的话,会传一个String的参数,它去匹配sku商品的标题。
那么通过这些搜索,我在详情页需要提供给前端什么数据去渲染呢?
在这里插入图片描述
以上截图来源京东,我的同学根据京东的页面模仿出部分功能,看完图中的标注,就应该会明白为什么模型会那么设计了。但是,还有一些其他的字段,那是涉及到商品详情页面的字段了。我们先说一说这个搜索页面吧。
搜索页面,中间这些属性、品牌是需要根据不同的搜索给出不同的答案的,所以,通过es中的聚合操作来实现的。
现在就是还有一个讨论的话题:是如何通过聚合得到这些信息的呢?
首先,后天管理员点击上架,会有对应的skuId,以及所属spu的信息,在上架的时候,我们会去数据库中查,将这些信息查到并且封装到SkuModel里,通过远程调用搜索服务,将这些数据存到es中。

如何存进ES的

接下来就看下es的索引映射的设计:

PUT product
{
  "mappings": {
    "properties": {
      "skuId": {
        "type": "long"
      },
      "spuId": {
        "type": "long"
      },
      "skuTitle": {
        "type": "text",//支持全文搜索的
        "analyzer": "ik_smart"//采用ik分词器
      },
      "skuPrice": {
        "type": "keyword"//必须输入精确值才能搜索
      },
      "skuImg": {
        "type": "keyword",//必须输入精确值才能搜索
        "index": false,//不能被索引
        "doc_values": false
      },
      "saleCount": {
        "type": "long"
      },
      "hosStock": {
        "type": "boolean"
      },
      "hotScore": {
        "type": "long"
      },
      "brandId": {
        "type": "long"
      },
      "catelogId": {
        "type": "long"
      },
      "brandName": {
        "type": "keyword",
        "index": false,
        "doc_values": false
      },
      "brandImg": {
        "type": "keyword",
        "index": false,
        "doc_values": false
      },
      "catelogName": {
        "type": "keyword",
        "index": false,
        "doc_values": false
      },
      "attrs": {
        "type": "nested",//es的嵌套模型
        "properties": {
          "attrId": {
            "type": "long"
          },
          "attrName": {
            "type": "keyword",
            "index": false,
            "doc_values": false
          },
          "attrValue": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

通过java操作ES的api:RestHighLevelClient来操作es的增删改查,接下来看看是如何存进去的

@Override
    public boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException {

		//1.在es中建立索引,建立号映射关系
        //2. 在ES中保存这些数据
        BulkRequest bulkRequest = new BulkRequest();
        for (SkuEsModel skuEsModel : skuEsModels) {
            //构造保存请求
            IndexRequest indexRequest = new IndexRequest(EsConstant.PRODUCT_INDEX);
            indexRequest.id(skuEsModel.getSkuId().toString());
            String jsonString = JSON.toJSONString(skuEsModel);
            indexRequest.source(jsonString, XContentType.JSON);
            bulkRequest.add(indexRequest);
        }


        BulkResponse bulk = esRestClient.bulk(bulkRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);

        //TODO 如果批量错误
        boolean hasFailures = bulk.hasFailures();

        List<String> collect = Arrays.asList(bulk.getItems()).stream().map(item -> {
            return item.getId();
        }).collect(Collectors.toList());

        log.info("商品上架完成:{}",collect);

        return hasFailures;
    }

如何从ES中查数据

查询的参数,我们也设计了一个模型来封装这些参数

@Data
public class SearchParam {
    /**
     * 页面传递过来的全文匹配关键字
     */
    private String keyword;
    /**
     * 品牌id,可以多选
     */
    private List<Long> brandId;
    /**
     * 三级分类id
     */
    private Long catalog3Id;
    /**
     * 排序条件:sort=price/salecount/hotscore_desc/asc
     */
    private String sort;
    /**
     * 是否显示有货
     */
    private Integer hasStock;
    /**
     * 价格区间查询
     */
    private String skuPrice;
    /**
     * 按照属性进行筛选
     */
    private List<String> attrs;
    /**
     * 页码
     */
    private Integer pageNum = 1;
    /**
     * 原生的所有查询条件
     */
    private String _queryString;
}

通过这些参数,然后去es中找到对应的索引下进行拼装查询,总结一下我在查询的步骤:

  1. 动态构建出查询需要的DSL语句
  2. 准备检索请求:1、模糊匹配,过滤(按照属性,分类,品牌,价格区间,库存),排序,分页,高亮,聚合分析 2、聚合:品牌聚合、分类聚合、属性聚合
  3. 执行检索请求
  4. 分析响应数据,封装成我们需要的格式
  5. 返回
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/MarkusZhang/article/details/108001353
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2022-12-29 21:50:46
  • 阅读 ( 242 )
  • 分类:Go应用

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢