第八章 全文检索【上】+商品添加ES + 商品热度排名

这篇具有很好参考价值的文章主要介绍了第八章 全文检索【上】+商品添加ES + 商品热度排名。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

es里的商品数据文件,电商项目,java,开发语言

一、商品检索功能介绍

根据用户输入的检索条件,查询出对用的商品

1.1 检索两个入口

首页的分类

es里的商品数据文件,电商项目,java,开发语言

 搜索栏

es里的商品数据文件,电商项目,java,开发语言

1.2 检索列表展示页面

es里的商品数据文件,电商项目,java,开发语言

1.3 根据业务搭建数据结构

1.3.1 建立mapping!

这时我们要思考三个问题:

  1. 哪些字段需要分词
    1.  例如:商品名称
  2. 我们用哪些字段进行过滤
    1. 平台属性值
    2. 分类Id
    3. 品牌Id
  3. 哪些字段我们需要通过搜索查询出来。
    1. 商品名称,价格,图片等。

以上分析的所有显示,以及分词,过滤的字段都应该在es中出现。Es中如何保存这些数据呢?

“根据上述的字段描述,应该建立一个mappings对应的存上上述字段描述的信息!”

根据以上制定出如下结构:mappings

Index:goods

type:_doc

document: properties - rows

field: id,price,title…

Es中index默认是true。

注意:ik_max_word 中文词库必须有!

attrs:平台属性值的集合,主要用于平台属性值过滤。

1.3.2 nested 介绍

nested:类型是一种特殊的对象object数据类型(specialised version of the object datatype ),允许对象数组彼此独立地进行索引和查询。

demo: 建立一个普通的index

如果linux 中有这个my_index 先删除!DELETE /my_index

步骤1:建立一个index

PUT my_index/_doc/1

{

  "group" : "fans",

  "user" : [

    {

      "first" : "John",

      "last" :  "Smith"

    },

    {

      "first" : "Alice",

      "last" :  "White"

    }

  ]

}

步骤2 : 执行查询

GET my_index/_search

{

  "query": {

    "bool": {

      "must": [

        { "match": { "user.first": "Alice" }},

        { "match": { "user.last":  "Smith" }}

      ]

    }

  }

}

查询结果:

es里的商品数据文件,电商项目,java,开发语言

能够查询出数据的原因是因为:建立my_index 的时候,它默认的数据类型是Object

{user.first:”John ,Alice”}

{user.last:”Smith,White”}

实际上:从业务的角度出发应该没有数据: 因为

User1 {John,Smith}

User2 {Alice,White}

是两个对象 而 {Alice,Smith} 在当前的user 中不存在!

步骤3:删除当前索引

DELETE /my_index

步骤4:建立一个nested 类型的

PUT my_index

{

  "mappings": {

      "properties": {

        "user": {

          "type": "nested"

        }

    }

  }

}

user字段映射为nested类型,而不是默认的object类型

重新执行步骤1,使用nested 查询

GET /my_index/_search

{

  "query": {

    "nested": {

      "path": "user",

      "query": {

        "bool": {

          "must": [

            {"match": {"user.first": "Alice"}},

            {"match": {"user.last": "Smith"}}

          ]

        }

      }

    }

  }

}

此查询得不到匹配,是因为AliceSmith不在同一个嵌套对象中。

   {"match": {"user.last": "White"}} 此时就会有数据:

1.4 搭建service-list服务

在service模块下搭建,搭建方式如service-item

1.4.1 修改配置pom.xml

<?xml version="1.0" encoding="UTF-8"?>
  <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.atguigu.gmall</groupId>
        <artifactId>service</artifactId>
        <version>1.0</version>
    </parent>

    <artifactId>service-list</artifactId>
    <version>1.0</version>

    <packaging>jar</packaging>
    <name>service-list</name>
    <description>service-list</description>

    <dependencies>
        <dependency>
            <groupId>com.atguigu.gmall</groupId>
            <artifactId>service-product-client</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
    </dependencies>
  </project>

说明:

  1. 引入service-product-client模块
  2. 引入spring-boot-starter-data-elasticsearch依赖

1.4.2  添加配置文件

bootstrap.properties

spring.application.name=service-list

  spring.profiles.active=dev

  spring.cloud.nacos.discovery.server-addr=192.168.200.129:8848

  spring.cloud.nacos.config.server-addr=192.168.200.129:8848

  spring.cloud.nacos.config.prefix=${spring.application.name}

  spring.cloud.nacos.config.file-extension=yaml

  spring.cloud.nacos.config.shared-configs[0].data-id=common.yaml

说明:添加es配置

1.4.3  构建实体与es mapping建立映射关系

package com.atguigu.gmall.model.list;
@Document(indexName = "goods", shards = 3, replicas = 1)
  @Data
  public class Goods {

    @Id
    private Long id;

    @Field(type = FieldType.Keyword, index = false)
    private String defaultImg;

    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String title;

    @Field(type = FieldType.Double)
    private Double price;

    @Field(type = FieldType.Date,format = DateFormat.custom, pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime; // 新品  

    @Field(type = FieldType.Long)
    private Long tmId;

    @Field(type = FieldType.Keyword)
    private String tmName;

@Field(type = FieldType.Keyword)
private String tmLogoUrl;



    @Field(type = FieldType.Long)
    private Long category1Id;

    @Field(type = FieldType.Keyword)
    private String category1Name;

    @Field(type = FieldType.Long)
    private Long category2Id;

    @Field(type = FieldType.Keyword)
    private String category2Name;

    @Field(type = FieldType.Long)
    private Long category3Id;

    @Field(type = FieldType.Keyword)
    private String category3Name;

    @Field(type = FieldType.Long)
    private Long hotScore = 0L;

    @Field(type = FieldType.Nested)
    private List<SearchAttr> attrs;

}
平台属性-平台属性值
@Data
  public class SearchAttr {

    @Field(type = FieldType.Long)
    private Long attrId;

    @Field(type = FieldType.Keyword)
    private String attrName;

    @Field(type = FieldType.Keyword)
    private String attrValue;

}

1.4.4  初始化mapping结构到es中

package com.atguigu.gmall.list.controller;
@RestController
@RequestMapping("api/list")
  public class ListApiController {

    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    /**
     * @return
     */
    @GetMapping("inner/createIndex")
    public Result createIndex() {

        restTemplate.createIndex(Goods.class);

        restTemplate.putMapping(Goods.class);

        return Result.ok();

    }

}

添加主启动类

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@ComponentScan({"com.atguigu.gmall"})
@EnableDiscoveryClient
@EnableFeignClients
(basePackages= {"com.atguigu.gmall"})
public class ServiceListApplication {
   
public static void main(String[] args) {

        SpringApplication.run(ServiceListApplication.
class,args);
    }
}

在浏览器运行:

http://localhost:8203/api/list/inner/createIndex

通过kibana查看mapping

es里的商品数据文件,电商项目,java,开发语言

 重点看:attrs 数据类型必须是nested !

二、商品上架,下架

构建goods数据模型分析

Sku基本信息(详情业务已封装了接口)

Sku分类信息(详情业务已封装了接口)

Sku的品牌信息(无)

Sku对应的平台属性(详情业务已封装了接口)

2.1 在service-product封装接口

2.1.1 Sku的品牌接口 

ManageService
/**
 * 通过品牌Id 来查询数据
 * @param tmId
 * @return
 */
  BaseTrademark getTrademarkByTmId(Long tmId);

实现类

@Autowired
  private BaseTrademarkMapper baseTrademarkMapper;
@Override
  public BaseTrademark getTrademarkByTmId(Long tmId) {
    return baseTrademarkMapper.selectById(tmId);
}
ProductApiController
/**
 * 通过品牌Id 集合来查询数据
 * @param tmId
 * @return
 */
  @GetMapping("inner/getTrademark/{tmId}")
  public BaseTrademark getTrademark(@PathVariable("tmId")Long tmId){
    return manageService.getTrademarkByTmId(tmId);
}

2.2 在service-product-client添加接口

ProductFeignClient
/**
 * 通过品牌Id 集合来查询数据
 * @param tmId
 * @return
 */

  @GetMapping("/api/product/inner/getTrademark/{tmId}")
BaseTrademark getTrademark(@PathVariable("tmId")Long tmId);
ProductDegradeFeignClient
@Override
  public BaseTrademark getTrademark(Long tmId) {
    return null;
}

2.3 实现商品上架,下架功能

2.3.1 封装接口

package com.atguigu.gmall.list.service;
public interface SearchService {

    /*
     * 上架商品列表
     * @param skuId
     */
    void upperGoods(Long skuId);
  

    /**
     * 下架商品列表
     * @param skuId
     */
    void lowerGoods(Long skuId);

}

2.3.2 制作操作es的接口

package com.atguigu.gmall.list.repository;

import com.atguigu.gmall.model.list.Goods;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

public interface GoodsRepository extends ElasticsearchRepository<Goods,Long> {


}

2.3.3 接口实现类

package com.atguigu.gmall.list.service.impl;

  @Service
  public class SearchServiceImpl implements SearchService 
  @Autowired
  private ProductFeignClient productFeignClient;

  @Autowired
  private GoodsRepository goodsRepository;

 /*
 * 上架商品列表
 * @param skuId
 */
  @Override
  public void upperGoods(Long skuId) {
    Goods goods = new Goods();
    //查询sku对应的平台属性
    List<BaseAttrInfo> baseAttrInfoList =  productFeignClient.getAttrList(skuId);
    if(null != baseAttrInfoList) {
        List<SearchAttr> searchAttrList =  baseAttrInfoList.stream().map(baseAttrInfo -> {
            SearchAttr searchAttr = new SearchAttr();

            searchAttr.setAttrId(baseAttrInfo.getId());

            searchAttr.setAttrName(baseAttrInfo.getAttrName());

            //一个sku只对应一个属性值

            List<BaseAttrValue> baseAttrValueList = baseAttrInfo.getAttrValueList();

            searchAttr.setAttrValue(baseAttrValueList.get(0).getValueName());

            return searchAttr;

        }).collect(Collectors.toList());

        goods.setAttrs(searchAttrList);

    }


    //查询sku信息
    SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);

    // 查询品牌
    BaseTrademark baseTrademark = productFeignClient.getTrademark(skuInfo.getTmId());

    if (baseTrademark != null){

        goods.setTmId(skuInfo.getTmId());

        goods.setTmName(baseTrademark.getTmName());
goods.setTmLogoUrl(trademark.getLogoUrl());
    }
  
    // 查询分类
    BaseCategoryView baseCategoryView = productFeignClient.getCategoryView(skuInfo.getCategory3Id());

    if (baseCategoryView != null) {
        goods.setCategory1Id(baseCategoryView.getCategory1Id());
        goods.setCategory1Name(baseCategoryView.getCategory1Name());
        goods.setCategory2Id(baseCategoryView.getCategory2Id());
        goods.setCategory2Name(baseCategoryView.getCategory2Name());
        goods.setCategory3Id(baseCategoryView.getCategory3Id());
        goods.setCategory3Name(baseCategoryView.getCategory3Name());
    }

    goods.setDefaultImg(skuInfo.getSkuDefaultImg());
    goods.setPrice(skuInfo.getPrice().doubleValue());
    goods.setId(skuInfo.getId());
    goods.setTitle(skuInfo.getSkuName());
    goods.setCreateTime(new Date());
    this.goodsRepository.save(goods);

}

  /**
 * 下架商品列表
 * @param skuId
  @Override
*/
  public void lowerGoods(Long skuId) {

    this.goodsRepository.deleteById(skuId);

}
}

2.3.4 控制器

package com.atguigu.gmall.list.controller;
  
  /**
 * 商品搜索列表接口
 */
  @RestController
@RequestMapping("api/list")
  public class ListApiController {

    @Autowired
    private SearchService searchService;

    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    /**
     * 上架商品
     * @param skuId
     * @return
     */
    @GetMapping("inner/upperGoods/{skuId}")
    public Result upperGoods(@PathVariable("skuId") Long skuId) {
        searchService.upperGoods(skuId);
        return Result.ok();

    }

    /**
     * 下架商品
     * @param skuId
     * @return
     */
    @GetMapping("inner/lowerGoods/{skuId}")
    public Result lowerGoods(@PathVariable("skuId") Long skuId) {
        searchService.lowerGoods(skuId);
        return Result.ok();
    }
}

添加数据

通过kibana查看数据

说明:后期学习了mq,我们可以根据后台系统添加和修改等操作,发送mq消息自动上下架商品

http://localhost:8203/api/list/inner/upperGoods/10

http://localhost:8203/api/list/inner/lowerGoods/10

三、商品热度排名

搜索商品时,后面我们会根据热点排序,何时更新热点?我们在获取商品详情时调用更新

3.1 封装接口与实现类与控制器

SearchService
/**
 * 更新热点
 * @param skuId
 */
  void incrHotScore(Long skuId);
实现类

@Autowired
private RedisTemplate redisTemplate;

@Override
  public void incrHotScore(Long skuId) {
    // 定义key
    String hotKey = "hotScore";
    // 保存数据
    Double hotScore = redisTemplate.opsForZSet().incrementScore(hotKey, "skuId:" + skuId, 1);

    if (hotScore%10==0){

        // 更新es
        Optional<Goods> optional = goodsRepository.findById(skuId);
        Goods goods = optional.get();
        goods.setHotScore(Math.round(hotScore));
        goodsRepository.save(goods);
    }
}

控制器

ListApiController
/**
 * 更新商品incrHotScore
 * @param skuId
 * @return
 */
  @GetMapping("inner/incrHotScore/{skuId}")
  public Result incrHotScore(@PathVariable("skuId") Long skuId) {
    // 调用服务层
    searchService.incrHotScore(skuId);
    return Result.ok();

}

3.2 在service-list-client封装接口

3.2.1 搭建service-list-client

搭建方式如service-item-client

3.2.2 修改pom.xml

<?xml version="1.0" encoding="UTF-8"?>
  <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.atguigu.gmall</groupId>
        <artifactId>service-client</artifactId>
        <version>1.0</version>
    </parent>
  
    <artifactId>service-list-client</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>
    <name>service-list-client</name>
    <description>service-list-client</description>

  </project>

3.2.3 添加接口

package com.atguigu.gmall.list.client;
@FeignClient(value = "service-list", fallback = ListDegradeFeignClient.class)
  public interface ListFeignClient {

   /**
 * 更新商品incrHotScore
 * @param skuId
 * @return
 */
  @GetMapping("/api/list/inner/incrHotScore/{skuId}")
Result incrHotScore(@PathVariable("skuId") Long skuId);
}
package com.atguigu.gmall.list.client.impl;
@Component
  public class ListDegradeFeignClient implements ListFeignClient {

    @Override
  public Result incrHotScore(Long skuId) {
    return null;
}
}

3.3 在service-item模块调用接口

引入依赖

<dependency>
   <groupId>com.atguigu.gmall</groupId>
   <artifactId>service-list-client</artifactId>
   <version>1.0</version>
</dependency>

接口调用文章来源地址https://www.toymoban.com/news/detail-709105.html

@Service
  public class ItemServiceImpl implements ItemService {

    @Autowired
    private ProductFeignClient productFeignClient;

      @Autowired
    private ListFeignClient listFeignClient;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Override
    public Map<String, Object> getBySkuId(Long skuId) {

        Map<String, Object> result = new HashMap<>();

       ...

        //获取分类信息
        CompletableFuture<Void> categoryViewCompletableFuture = skuCompletableFuture.thenAcceptAsync(skuInfo -> {

            BaseCategoryView categoryView = productFeignClient.getCategoryView(skuInfo.getCategory3Id());

            //分类信息

            result.put("categoryView", categoryView);

        }, threadPoolExecutor);

  

        //更新商品incrHotScore

        CompletableFuture<Void> incrHotScoreCompletableFuture = CompletableFuture.runAsync(() -> {

            listFeignClient.incrHotScore(skuId);

        }, threadPoolExecutor);

  
        CompletableFuture.allOf(skuCompletableFuture, spuSaleAttrCompletableFuture, skuValueIdsMapCompletableFuture,skuPriceCompletableFuture, categoryViewCompletableFuture, incrHotScoreCompletableFuture).join();

        return result;

    }

}

到了这里,关于第八章 全文检索【上】+商品添加ES + 商品热度排名的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 商城-学习整理-高级-全文检索-ES(九)

    https://www.elastic.co/cn/what-is/elasticsearch Elastic 的底层是开源库 Lucene。但是,你没法直接用 Lucene,必须自己写代码去调用它的接口。Elastic 是 Lucene 的封装,提供了 REST API 的操作接口,开箱即用。 REST API:天然的跨平台。 官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/cur

    2024年02月12日
    浏览(32)
  • MySQL全文检索临时代替ES实现快速搜索

    引入 在MySQL 5.7.6之前,全文索引只支持英文全文索引,不支持中文全文索引,需要利用分词器把中文段落预处理拆分成单词,然后存入数据库。 从MySQL 5.7.6开始,MySQL内置了ngram全文解析器,用来支持中文、日文、韩文分词。 全文索引只支持InnoDB和MyISAM引擎,支持的类型为C

    2024年02月07日
    浏览(33)
  • 【ElasticSearch-基础篇】ES高级查询Query DSL全文检索

    和术语级别查询(Term-Level Queries)不同,全文检索查询(Full Text Queries)旨在 基于相关性搜索和匹配文本数据 。这些查询会对输入的文本进行分析,将其 拆分 为词项(单个单词),并执行诸如分词、词干处理和标准化等操作。 全文检索的关键特点: 对输入的文本进行分析

    2024年01月22日
    浏览(40)
  • ES全文检索pdf、word、txt等文本文件内容

    需求: 用ES对上传文件内容的检索和高亮显示。 之前从事于物联网行业,从多年前了解ES以后没有使用过,本篇文章就是为了记录小白用ES完成工作的过程。 Elasticsearch的介绍、安装和环境这里不过多介绍,网上有很多。 思考: 文本搜索,文本需要上传elasticsearch。支持

    2024年04月11日
    浏览(49)
  • 如何实现 Es 全文检索、高亮文本略缩处理(封装工具接口极致解耦)

    最近手上在做 Es 全文检索的需求,类似于百度那种,根据检索出对应的文章,然后高亮显示,特此记录一下,其实主要就是处理 Es 数据那块复杂,涉及到高亮文本替换以及高亮字段截取,还有要考虑到代码的复用性,是否可以将转换代码抽离出来,提供给不同结构的

    2024年02月08日
    浏览(31)
  • 17、全文检索 -- Elasticsearch -- 使用 反应式 RestClient (ReactiveElasticsearchClient)操作 Es 服务器(增、删、查 :索引库和文档)

    Elasticsearch 所提供 RestHighLevelClient 本身提供了 【同步编程】 和 【异步编程】两种模型。 Elasticsearch 官方并未提供反应式的 RestClient : 因此 Spring Data Elasticsearch 额外补充了一个 ReactiveElasticsearchClient,用于提供反应式API支持, ReactiveElasticsearchClient 相当于 RestHighLevelClient 的反应式

    2024年04月28日
    浏览(34)
  • ES是一个分布式全文检索框架,隐藏了复杂的处理机制,核心数据分片机制、集群发现、分片负载均衡请求路由

    ES是一个分布式框架,隐藏了复杂的处理机制,核心数据分片机制、集群发现、分片负载均衡请求路由。 ES的高可用架构,总体如下图: 说明:本文会以pdf格式持续更新,更多最新尼恩3高pdf笔记,请从下面的链接获取:语雀 或者 码云 ES基本概念名词 Cluster 代表一个集群,集

    2024年02月10日
    浏览(28)
  • 18、全文检索--Elasticsearch-- SpringBoot 整合 Spring Data Elasticsearch(异步方式(Reactive)和 传统同步方式 分别操作ES的代码演示)

    启动命令行窗口,执行:elasticsearch 命令即可启动 Elasticsearch 服务器 三种查询方式解释: 方法名查询: 就是全自动查询,只要按照规则来定义查询方法 ,Spring Data Elasticsearch 就会帮我们生成对应的查询语句,并且生成方法体。 @Query 查询 : 就是半自动查询, 按照 S

    2024年03月12日
    浏览(50)
  • 全文检索-Elasticsearch-进阶检索

    本文记录谷粒商城高级篇的 Elasticsearch 进阶检索部分,续上之前记录的 Elasticsearch入门篇。 ES 支持两种基本方式检索 : 一个是通过使用 REST request URI 发送搜索参数(uri + 检索参数) 另一个是通过使用 REST request body 来发送它们(uri + 请求体) 请求体中写查询条件,语法: 示例

    2024年02月03日
    浏览(74)
  • 【全文检索】sqlite-fts4和pgsql的全文检索对比

    因为是Android项目,老系统中的全文检索是采用sqlite自带的fts4,然而后续由于地图要素全部转为线上,全文检索也需要同步在线查询,所以将整个全文检索的功能迁移到pgsql中。目前这块功能基本结束,这里来对两种全文检索方案做一个对比总结。 相比与fts5,fts4的好处是原生

    2024年02月05日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包