一篇文章快速学会Elasticsearch在实战中的使用(附高清脑图)

目录

引言

一、为什么要使用Elasticsearch

二、什么是Elasticsearch

三、Elasticsearch相关

(一)Kibana

(二)IK分词器

四、Elasticsearch的使用

(一)将数据导入Elasticsearch的索引库

Ⅰ、创建搜索微服务

Ⅱ、索引库数据格式分析

Ⅲ、商品微服务提供接口

Ⅳ、导入数据

(二)实现基本的搜索

Ⅰ、页面发送搜索请求

Ⅱ、Controller

Ⅲ、Service

(三)搜索过滤

Ⅰ、过滤功能分析

Ⅱ、生成分类和品牌的过滤

Ⅲ、生成规格参数过滤

Ⅳ、过滤条件的筛选

(四)Elasticsearch索引库与数据库的数据同步

五、高清脑图


 

 

引言

最近在回顾整理,把之前写的项目中的搜索模块的相关内容回顾了一下,做了个关于 Elasticsearch在项目中使用 的脑图,分享出来给大家有需要的人。我顺便再用文章写一遍加深一下印象,然后加一些脑图上不好写的。(都是些基础的使用,适合需要学习使用的初学者,大佬还请无视~)

 

一、为什么要使用Elasticsearch

作为一个商城,搜索功能至关重要。用户一般访问一个商城网站,基本上都是已经有了某样商品的购买需求,进入商城网站后就会直接搜索该类商品。这个时候,搜索速度和搜索结果的准确性就显得非常重要了。不论是 搜索速度慢,还是搜索结果不准确,都是会严重影响用户体验,造成用户流失。

传统的搜索是直接访问数据库来搜索,一旦数据量和访问量上升了,对数据库的压力非常大,极有可能造成数据库服务宕机。就算服务器能抗住访问量,搜索速度也会很慢。你可能会说,给数据库建个索引,确实,这样是会快很多,但是相比Elasticsearch来说,还是比较慢了。并且注意一点,加了索引之后,搜索效果就不好了,前置模糊查询时,会使索引失效,然后变成全表扫描,大数据量的时候,来个全表扫描? 太恐怖了!!!

所以,这个时候就该 Elasticsearch上场了~~~

 

二、什么是Elasticsearch

官网说明:Elasticsearch 是一个分布式的RESTful风格的搜索和数据分析引擎,能够解决不断涌现的各种用例。作为Elastic Stack 的核心,它集中存储了您的数据,帮助您发现意料之中以及意料之外的情况。👉官网

 简单来说Elasticsearch是一个搜索引擎,并且可以对数据进行分析。

Elasticsearch的一些特点:

  1. 分布式,无需人工搭建集群,并尽力隐藏分布式系统的复杂性。
  2. RESTful,API遵循REST原则,容易上手。
  3. 对海量数据进行近实时的处理

 

 

 

三、Elasticsearch相关

(一)Kibana

Kibana是一个基于Node.js的Elasticsearch索引库数据统计工具,可以利用Elasticsearch的聚合功能,生成各种图表,如柱形图,线状图,饼图等。并且Kibana还提供了操作Elasticsearch索引数据的控制台,还API提示,不论是学习Elasticsearch的时候,还是使用Elasticsearch的时候,都很方便,用处也很大。

(二)IK分词器

项目中使用的一个中文分词器,想深入了解的可以去ik的社区看看:ik分词器社区

 

(这两个以及Elasticsearch的基础概念和语法 这里就不详述了,本文重点不在这。)

 

 

 

四、Elasticsearch的使用

 

(一)将数据导入Elasticsearch的索引库

 

Ⅰ、创建搜索微服务

我用Springboot搭的,没什么好说的,注意配置文件配置一下节点和默认名称。

spring:
  application:
    name: search-service
  data:
    elasticsearch:
      cluster-name: elasticsearch #默认其实就是elasticsearch,但最好还是配置一下
      cluster-nodes: xxx.xxx.xxx.xxx:9301 #节点地址和端口

(我没用集群,需要使用集群的可以去找一下大佬写的教程。)

 

Ⅱ、索引库数据格式分析

1.首先作为一个商城项目,搜索结果是一个个的SPU,既多个SKU的集合。
所以索引库中存储的应该也是SPU,但是要包含SKU的信息。

2.为了方便后面实现搜索的过滤,所以我们的搜索结果不仅需要 图片、价格、标题、SpuId、SkuId,
还需要搜索过滤条件 商品分类、品牌、创建时间等可用来搜索的规格参数等数据。

3.最终数据结构参考

@Document(indexName = "goods", type = "docs", shards = 1, replicas = 0)
public class Goods {
    @Id
    private Long id; // spuId
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String all; // 用来进行全文检索的字段,里面包含标题、商品分类,品牌等信息
    @Field(type = FieldType.Keyword, index = false)
    private String subTitle;// 卖点
    private Long brandId;// 品牌id
    private Long cid1;// 1级分类id
    private Long cid2;// 2级分类id
    private Long cid3;// 3级分类id
    private Date createTime;// 创建时间,用于搜索过滤时的 最新 
    private List<Long> price;//价格数组,是所有sku的价格集合。方便根据价格进行筛选过滤
    @Field(type = FieldType.Keyword, index = false)
    private String skus;// List<sku>信息的json结构,用于页面展示的sku信息,不索引,不搜索。包含skuId、image、price、title字段
    private Map<String, Object> specs;// 可搜索的规格参数,key是参数名,值是参数值。例如:我们在specs中存储 内存:8G,256G,颜色为黑色,
}

 

 

Ⅲ、商品微服务提供接口

1. 为了避免代码冗余,降低开发成本。商品微服务方不仅提供实体类的相关方法,还提供这些方法的api接口声明。
搜索微服务及其他服务需要使用时,直接继承并调用该api接口即可使用。

即:商品的微服务要提供相关实体类的API接口,当我们搜索微服务或者其他微服务需要使用该实体类,只需使用一个接口继承该API接口,然后调用即可。

 

 

Ⅳ、导入数据

我使用的是 Spring Data Elasticsearch来操作。
Spring Data 的强大之处,就在于你不用写任何DAO处理,自动根据方法名或类的信息进行CRUD操作。只要你定
义一个接口,然后继承Repository提供的一些子接口,就能具备各种基本的CRUD功能。
我们只需要定义接口,然后继承它就OK了。(就像使用Mapper接口操作数据库一样)

1. 创建 xxxRepository接口

public interface GoodsRepository extends ElasticsearchRepository<Goods,Long>{

}

2. 创建索引 createIndex()
 

3. 导入数据
查询出所需要的数据,根据需要的字段,把查询到的SPU构建成所需要的goods,然后调用xxxRepository写入刚刚创建的索引库。

(这个数据导入一次就可以了,后面的数据同步用的是别的方法。)

 

(二)实现基本的搜索

Ⅰ、页面发送搜索请求

页面发送过来的请求包括 搜索字段 和 分页page,排序字段,是否降序等字段, 所以后台要有相关对象来接收这些字段。

可以新建一个对象,继承已有对象并扩展,这样不会影响到已写好的功能。

 

Ⅱ、Controller

获取请求中的内容,并调用Service处理,然后返回。

 

Ⅲ、Service

1.自定义查询构建器NativeSearchQueryBuilder

2.添加查询条件

3.添加分页,分页页码从0开始

4.添加结果集过滤

5.执行查询,获取结果集

6.封装结果集并返回

 

查询结果中可能会有空值,可以通过如下设置来忽略:
 

spring:
  jackson:
    default-property-inclusion: non_null # 配置json处理时忽略空值

 


 

(三)搜索过滤

Ⅰ、过滤功能分析

根据用户输入的搜索字段,查出相应的可供用于过滤的字段
比如,用户搜索手机,那我们可以提供出所有手机的 品牌,规格参数 等,供用户选择来过滤。
比如,用户搜索 苹果手机,那我们可以提供出苹果品牌下的所有手机的 款式,规格 等,供用户来选择过滤。
 

Ⅱ、生成分类和品牌的过滤

1.分析

分类和品牌。在我们的数据库中已经有所有的分类和品牌信息。那在这个位置,是不是把所有的分类和品牌信息都展示出来呢?
显然不是,用户搜索的条件会对商品进行过滤,而在搜索结果中,不一定包含所有的分类和品牌,直接展示出所有商品分类,让用户选择显然是不合适的。
比如,用户搜索一个手机,结果你给用户提供的过滤选项是所有的商品的分类和品牌,那体验就特别差了。
所以无论是分类信息,还是品牌信息,都应该从搜索的结果商品中进行聚合得到。

 

2.扩展返回的结果

分类:需要 分类名称,以及绑定分类id信息
品牌 :logo,文字,id ,基本是品牌的完整信息
扩展:新建一个类,继承PageResult,扩展两个新属性,分类集合 、品牌集合。
(为什么是新建一个类继承,而不是在原类上修改?因为如果在原类上修改,会影响之前已经写好的相关方法。)
 

3.聚合商品分类和品牌

①处理聚合结果集

②获取所有的品牌(或分类)的id桶

③定义一个品牌(或分类)的集合,搜集所有的品牌(或分类)对象

④解析所有的id桶,查询品牌(或分类)

 

 

Ⅲ、生成规格参数过滤

要先考虑几个问题:

  • 什么时候显示规格参数过滤? 分类只有一个
  • 如何知道哪些规格需要过滤?
  • 要过滤的参数,其可选值是如何获取的?
  • 规格过滤的可选值,其数据格式怎样的?

 

什么情况下显示有关规格参数的过滤?

如果用户尚未选择商品分类,或者聚合得到的分类数大于1,那么就没必要进行规格参数的聚合。因为不同分类的商品,其规格是不同的。

因此,我们在后台需要对聚合得到的商品分类数量进行判断,如果等于1,我们才继续进行规格参数的聚合。

 

如何知道哪些规格需要过滤?

我们不能把数据库中的所有规格参数都拿来过滤。因为并不是所有的规格参数都可以用来过滤,参数的值是不确定的。

所以我们在设计规格参数时,要标记某些规格可搜索,某些不可搜索。

如此,一旦商品分类确定,我们就可以根据商品分类查询到其对应的规格,从而知道哪些规格要进行搜索。

 

要过滤的参数,其可选值是如何获取的?

虽然数据库中有所有的规格参数,但是不能把一切数据都用来供用户选择。

与商品分类和品牌一样,应该是从用户搜索得到的结果中聚合,得到与结果品牌的规格参数可选值。

 

规格过滤的可选值,其数据格式怎样的?

根据不同规格,可以分为字符串类型,或者数值范围类型 等。

 

 

Ⅳ、过滤条件的筛选


1.前台发生过滤请求到后台

2.在SearchService中的search方法中添加过滤查询方法

 

 

(四)Elasticsearch索引库与数据库的数据同步

数据同步使用的是RabbitMQ消息队列;

消息模型选择的 订阅模型-Topic。

当商品微服务对商品进行 增、删、改 操作时,需要向消息队列的交换机中发送消息;
然后由交换机根据RoutingKey把增删改的相关消息路由到搜索微服务监听的队列;
搜索微服务监听到增删改消息后,对Elasticsearch索引库进行增删改。实现数据的同步。

 

 

五、高清脑图

(需要脑图文件的可也以中评论里留言邮箱) :

 

写在最后:本文主要是给初学者一个大概的使用过程,很多问题,还是要多去使用,在实践中学习。

                         

                                     文章里可能有些地方写的不好或者不对,欢迎留言指出。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章