一篇文章快速學會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索引庫進行增刪改。實現數據的同步。

 

 

五、高清腦圖

(需要腦圖文件的可也以中評論裏留言郵箱) :

 

寫在最後:本文主要是給初學者一個大概的使用過程,很多問題,還是要多去使用,在實踐中學習。

                         

                                     文章裏可能有些地方寫的不好或者不對,歡迎留言指出。

 

 

 

 

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