你想要擁有自己的搜索引擎嗎?

轉載本文需註明出處:微信公衆號EAWorld,違者必究。


前言:


在現代開發的應用系統中,無論是常規的web應用,還是近幾年興起的app應用,或者是風頭正熱的大數據應用,都離不開搜索這一功能,搜索也是在應用系統中使用頻率最高的一個功能,比如普通的商城系統中的商品搜索或者一些資源的站內搜索等。

大多數的應用系統的搜索都是針對數據庫的搜索,比如說對某個表做一個按名稱或針對某些字段的描述做模糊查詢。更高級一點的是可以對搜索關鍵字進行分詞,並且專門建一個搜索詞庫表,這種做法需要對搜索詞進行拆解然後冪集組合並與目標表的ID關聯,搜索字與詞庫表的字以完全匹配的方式查詢並找到目標表的ID,這種搜索的解決方案需要拆解相關數據庫表建立索引,相對比較麻煩。

所以,今天我們就來聊聊近兩年興起的分佈式搜索引擎技術——Elasticsearch。


1.什麼是搜索?


百度、Google:我們想尋找一個我們喜歡的小說、電影或者新聞等就可以去百度或者Google搜索一下。
互聯網搜索:電商網站搜索商品,招聘網站搜索工作崗位,租房網站搜索房屋信息等。
企業應用系統的搜索:企業員工搜索,會議搜索,公文搜索等。


2.Elasticsearch是如何產生的?


1. 思考:百億、千億級海量數據是如何搜索的?


當系統數據量達到億以上量級的時候,我們系統架構通常會從哪些角度去思考解決方案呢?


1)用什麼數據庫好?(mysql、db2、oracle、sqlserver、hbase等)
2)如何解決高併發和單點故障;(緩存、消息隊列、系統拆分、讀寫分離、分庫分表等)
3)如何保證數據庫的高可用性和數據安全性;(冷備份、熱備份、異地多活等)
4)如何解決數據檢索效率難題;(數據庫代理中間件:mysql-proxy、Cobar、mycat等;)

5)如何解決統計分析問題;(離線統計、近實時統計等) 


2. 關係型數據庫的解決方案


對於像mysql這樣的傳統關係型數據庫,在以往的項目中,我們使用了以下架構方案去優化數據庫的查詢和寫入瓶頸:


1) 通過主從備份來保證數據不會丟失,從而解決數據安全性問題;
2) 通過數據庫代理中間件對數據庫進行心跳監測,解決單點故障問題;
3) 通過消息隊列對同一時段的大量請求進行削峯處理,解決高併發問題;
4) 通過數據庫代理中間件將查詢語句分發到各個slave節點進行查詢,並彙總結果,提高查詢效率;
5) 對於某些不需要實時統計的場景,如統計前一天的XX數據,通過離線計算並存儲到緩存中,解決某些場景的統計問題;


問題:上述方案可以優化一部分搜索性能的問題,但是由於關係型數據庫本身的特性,上述方案實施起來並不是一件容易的事,涉及到很多的組件,然而一個系統多一個組件,要保證其系統的穩定性的難度就會成幾何指數增加,而且就算目前解決的問題,以後數據量再上升到一個量級時,此方案如何進一步擴展又是一份挑戰。



3. 非關係型數據庫的解決方案
對於像mongodb這樣的nosql數據庫,在以往的項目中,我們使用了以下架構方案去解決數據庫的查詢和寫入瓶頸:


1)通過副本備份保證數據安全性;
2)通過節點競選機制解決單點問題;
3)先從配置庫檢索分片信息,然後將請求分發到各個節點,最後由路由節點合併彙總結果 


問題:mongodb這樣的nosql數據庫對於簡單單表查詢的效率是毋庸置疑的,但是它並不能很容易的做到複雜的多表聚合查詢,比如涉及到多個表的的關聯查詢就會顯得有些力不從心。



4. 如果我們把數據全部放到內存會怎麼樣?
假設我們現在有1PB的數據,按照每個節點128G內存來計算,在內存完全裝滿數據的情況下,我們一共需要的機器數量是:1PB=1024T=1048576G,節點數=1048576/128 =8192個,再考慮到數據的備份問題,往往實際場景下我們需要的機器會超過2W臺,這樣巨大的成本決定了其是不現實的!


所以,從前面討論的情況來看,無論是把數據存到傳統的基於磁盤的數據庫中,還是把數據放到內存中,都無法完全解決大數據量下的搜索問題,根據這一情況,讓我們從源頭來思考一下:


1)數據和索引需要分離;
2)數據量過大時,數據需要壓縮;
3)數據存儲需要有序;
4)到達瓶頸時,要能夠快捷、方便、無感知的進行水平拓展;
 

由此我們就引出了當下十分流行的分佈式搜索引擎技術:Elasticsearch。

3.Elasticsearch基礎


1. Elasticsearch是什麼?

Elasticsearch是一個基於Apache Lucene(TM)的開源的高擴展的分佈式搜索引擎 ,它可以近乎實時的存儲、檢索數據;本身擴展性很好,可以很輕鬆的擴展到上百臺服務器,處理PB級別的數據。


2. Lucene是什麼?

Lucene是一套用於全文檢索和搜尋的開源程式庫,由Apache軟件基金會支持和提供。Lucene提供了一個簡單卻強大的應用程式接口,能夠做全文索引和搜尋。在Java開發環境裏Lucene是一個成熟的免費開源工具。就其本身而言,Lucene是當前以及最近幾年最受歡迎的免費Java信息檢索程序庫。——《百度百科》 簡單來說,Lucene就是一個jar包,裏面包含了一系列的和搜索相關的方法,java工程只需要引入Lucene相關的jar包,就可以進行開發。


3. Lucene與Elasticsearch之間的關係


1)lucene,最先進、功能最強大的搜索庫,直接基於lucene開發,非常複雜,api複雜(實現一些簡單的功能,寫大量的java代碼),需要深入理解原理(各種索引結構) 。


2)elasticsearch,基於lucene,隱藏其開發的複雜性,提供簡單易用的restful api接口、java api接口(還有其他語言的api接口) ,從而使我們能夠更方便的實現搜索功能。


3) elasticsearch不僅僅是Lucene和全文搜索引擎 ,它還具有以下特點:

    分佈式的實時文件存儲,每個字段都被索引並可被搜索
    實時分析的分佈式搜索引擎
    可以擴展到上百臺服務器,處理PB級結構化或非結構化數據

4. Elasticsearch 核心概念


1) 近實時(NRT)  Elasticsearch是一個接近實時的搜索平臺。這意味着,往索引插入一個文檔直到這個文檔能夠被搜索到有一個輕微的延遲(通常是1秒)。



2) 集羣(cluster) 集羣由一個或多個節點組成,當有多個節點時,其中有一個爲主節點,這個主節點是可以通過選舉產生的,主從節點是對於集羣內部來說的。es的一個概念就是去中心化,字面上理解就是無中心節點,這是對於集羣外部來說的,因爲從外部來看es集羣,在邏輯上是個整體,你與任何一個節點的通信和與整個es集羣通信是等價的。 


3) 節點(node) 運行了單個實例的ES主機稱爲節點,它是集羣的一個成員,可以存儲數據、參與集羣索引及搜索操作。類似於集羣,節點靠其名稱進行標識,默認爲啓動時自動生成的隨機Marvel字符名稱。用戶可以按需要自定義任何希望使用的名稱,但出於管理的目的,此名稱應該儘可能有較好的識別性。節點通過爲其配置的ES集羣名稱確定其所要加入的集羣。


4)分片(shards) 代表索引分片,es可以把一個完整的索引分成多個分片(shards),這樣的好處可以橫向擴展,存儲更多數據,讓搜索和分析等操作分佈到多臺服務器上去執行,提升吞吐量和性能。分片的數量只能在索引創建前指定,並且索引創建後不能更改。


5)副本(replica) 任何一個服務器隨時可能故障或宕機,此時shard可能就會丟失,因此可以爲每個shard創建多個replica副本。replica可以在shard故障時提供備用服務,保證數據不丟失,多個replica還可以提升搜索操作的吞吐量和性能。primary shard(建立索引時一次設置,不能修改,默認5個),replica shard(隨時修改數量,默認1個),默認每個索引10個shard,5個primary shard,5個replica shard,最小的高可用配置,是2臺服務器。


6)索引 (index) 包含一堆有相似結構的文檔數據,比如可以有一個用戶信息索引,商品信息索引,訂單信息索引等,一個索引由一個名字來標識(必須全部是小寫字母的),並且當我們要對對應於這個索引中的文檔進行索引、搜索、更新和刪除的時候,都要使用到這個名字。索引類似於關係型數據庫中Database的概念。在一個集羣中,如果你想,可以定義任意多的索引。


7)類型(type) 每個索引裏都可以有一個或多個type,type是index中的一個邏輯數據分類,一個type下的document,都有相同的field,比如博客系統,有一個索引,可以定義用戶數據type,博客數據type,評論數據type等。類型類似於關係型數據庫中Table的概念。


8)文檔(document) document是es中的最小數據單元,一個document可以是一條客戶數據,一條商品分類數據,一條訂單數據,通常用JSON數據結構表示,每個index下的type中,都可以去存儲多個document。一個document裏面有多個field,每個field就是一個數據字段。


舉例:


商品index,裏面存放了所有的商品數據,商品document


但是商品分很多種類,每個種類的document的field可能不太一樣,比如說電器商品,可能還包含一些諸如售後時間範圍這樣的特殊field;生鮮商品,還包含一些諸如生鮮保質期之類的特殊field


type,日化商品type,電器商品type,生鮮商品type


日化商品type:product_id,product_name,product_desc,category_id,category_name;


電器商品type:product_id,product_name,product_desc,category_id,category_name,service_period;


生鮮商品type:product_id,product_name,product_desc,category_id,category_name,eat_period;


每一個type裏面,都會包含一堆document


{ "product_id": "2", "product_name": "長虹電視機", "product_desc": "4k高清", "category_id": "3", "category_name": "電器", "service_period": "1年"}


{ "product_id": "3", "product_name": "基圍蝦", "product_desc": "純天然,冰島產", "category_id": "4", "category_name": "生鮮", "eat_period": "7天"}


5. elasticsearch核心概念 vs. 數據庫核心概念



6. Elasticsearch的功能


1)分佈式的搜索引擎和數據分析引擎


搜索:百度,網站的站內搜索,IT系統的檢索;
數據分析:電商網站,最近7天牙膏這種商品銷量排名前10的商家有哪些;新聞網站,最近1個月訪問量排名前3的新聞版塊是哪些;


2)全文檢索,結構化檢索,數據分析


全文檢索:我想搜索商品名稱包含洗髮水的商品,select * from products where product_name like "%洗髮水%";

結構化檢索:我想搜索商品分類爲糧油用品的商品都有哪些,select * from products where category_type='糧油用品';
部分匹配、自動完成、搜索糾錯、搜索推薦等;
數據分析:我們分析每一個商品分類下有多少個商品,select category_type,count(*) from products group by category_type;


3)對海量數據進行近實時的處理
分佈式:ES自動可以將海量數據分散到多臺服務器上去存儲和檢索;
海量數據的處理:分佈式以後,就可以採用大量的服務器去存儲和檢索數據,自然而然就可以實現海量數據的處理了;
近實時:檢索個數據要花費1小時(這就不叫近實時,叫離線批處理);在秒級別對數據進行搜索和分析;
跟分佈式/海量數據相反的:lucene,單機應用,只能在單臺服務器上使用,最多隻能處理單臺服務器可以處理的數據量。

7. Elasticsearch的特點


1)可以作爲一個大型分佈式集羣(數百臺服務器)技術,處理PB級數據,服務大公司;也可以運行在單機上,服務小公司


2)Elasticsearch不是什麼新技術,主要是將全文檢索、數據分析以及分佈式技術,合併在了一起,才形成了獨一無二的ES;lucene(全文檢索)+數據分析軟件+分佈式數據庫(mycat)


3)對用戶而言,是開箱即用的,非常簡單,作爲中小型的應用,直接3分鐘部署一下ES,就可以作爲生產環境的系統來使用了,數據量不大,操作不是太複雜


4)數據庫的功能面對很多領域是不夠用的(事務,還有各種聯機事務型的操作);特殊的功能,比如全文檢索,同義詞處理,相關度排名,複雜數據分析,海量數據的近實時處理;Elasticsearch作爲傳統數據庫的一個補充,提供了數據庫所不不能提供的很多功能

8. Elasticsearch的適用場景


國外


1)維基百科,類似百度百科,牙膏,牙膏的維基百科,全文檢索,高亮,搜索推薦


2)The Guardian(國外新聞網站),類似搜狐新聞,用戶行爲日誌(點擊,瀏覽,收藏,評論)+社交網絡數據(對某某新聞的相關看法),數據分析,給到每篇新聞文章的作者,讓他知道他的文章的公衆反饋(好,壞,熱門,垃圾,鄙視,崇拜)


3)Stack Overflow(國外的程序異常討論論壇),IT問題,程序的報錯,提交上去,有人會跟你討論和回答,全文檢索,搜索相關問題和答案,程序報錯了,就會將報錯信息粘貼到裏面去,搜索有沒有對應的答案


4)GitHub(開源代碼管理),搜索上千億行代碼


5)電商網站,檢索商品


6)日誌數據分析,logstash採集日誌,ES進行復雜的數據分析(ELK技術,elasticsearch+logstash+kibana)


7)商品價格監控網站,用戶設定某商品的價格閾值,當低於該閾值的時候,發送通知消息給用戶,比如說訂閱牙膏的監控,如果高露潔牙膏的家庭套裝低於50塊錢,就通知我,我就去買


8)BI系統,商業智能,Business Intelligence。比如說有個大型商場集團,BI,分析一下某某區域最近3年的用戶消費金額的趨勢以及用戶羣體的組成構成,產出相關的數張報表,XX區,最近3年,每年消費金額呈現100%的增長,而且用戶羣體85%是高級白領,開一個新商場。ES執行數據分析和挖掘,Kibana進行數據可視化


國內


站內搜索(電商,招聘,門戶,等等),IT系統搜索(OA,CRM,ERP,等等),數據分析(ES熱門的一個使用場景)等


4.Elasticsearch倒排索引


上面一小段我們討論了Elasticsearch的一些基本信息,這一小段我們來聊一聊Elasticsearch的倒排索引。


倒排索引(Inverted Index)也叫反向索引,有反向索引必有正向索引。通俗地來講,正向索引是通過key尋找value,反向索引則是通過value尋找key。 


我們先來看一下es是如何插入一條索引數據的:

curl -X PUT "localhost:9200/user/_doc/1" -H 'Content-Type: application/json' -d'{    "name" : "mary",    "gender" : 0,    "age" : 25}

(左右滑動查看全部代碼)


就是直接PUT一個JSON的對象,這個對象有多個字段,在插入這些數據到索引的同時,Elasticsearch還爲這些字段建立索引——倒排索引,Elasticsearch最核心功能是搜索 ,建立倒排索引,就是爲了提高搜索的性能。


那麼倒排索引是什麼樣子的呢?



首先我們來搞清楚幾個概念:


1)Term(單詞):一段文本經過分析器分析以後就會輸出一串單詞,這一個一個的就叫做Term(直譯爲:單詞) ;


2)Term Dictionary(單詞字典):顧名思義,它裏面維護的是Term,可以理解爲Term的集合;


3)Term Index(單詞索引):爲了更快的找到某個單詞,我們爲單詞建立索引 ;


4)Posting List(倒排列表):倒排列表記錄了出現過某個單詞的所有文檔的文檔列表及單詞在該文檔中出現的位置信息,每條記錄稱爲一個倒排項(Posting)。根據倒排列表,即可獲知哪些文檔包含某個單詞 ;


類比我們的新華詞典,那麼Term就相當於詞語,Term Dictionary相當於漢語詞典本身,Term Index相當於詞典的目錄索引。


下面再來舉個例子看一看:


假設有個user索引,它有四個字段:分別是name,gender,age,address。大概是下面這個樣子,跟關係型數據庫一樣 :



對於這張表中的數據,Elasticsearch建立的索引大致如下:


name字段:



age字段:



gender字段:



address字段:



Elasticsearch分別爲每個字段都建立了一個倒排索引。比如,在上面“麗麗”、“北京市”、18 這些都是Term,而[2,3]就是Posting List。Posting list就是一個數組,存儲了所有符合某個Term的文檔ID;


在倒排索引中,通過Term索引可以找到Term在Term Dictionary中的位置,進而找到Posting List,有了倒排列表就可以根據ID找到文檔了 ;


如果類比數據庫的數據存儲引擎的話:Term Index相當於索引文件,Term Dictionary相當於數據文件);


從最開始的那張圖中,我們將倒排索引分成了三步,實際上我們可以把Term Index和Term Dictionary看成一步,就是找term;因此我們也可以這樣理解倒排索引:通過單詞找到對應的倒排列表,根據倒排列表中的倒排項進而可以找到文檔記錄。


5.Springboot整合Elasticsearch


上面給大家介紹了Elasticsearch相關的一些基本知識,由於篇幅有限,關於Elasticsearch的安裝和基本使用方法請大家去閱讀官網的資料,這裏就不再贅述


https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html


話不多說讓我們來看看如何將Elasticsearch整合到一個springboot項目中:


1. 集成方式


Spring Boot中集成Elasticsearch有4種方式:


1)REST Client
2)Jest
3)Spring Data Elasticsearch Template
4)Spring Data Elasticsearch Repositories


本文用後面兩種方式來分別連接並操作Elasticsearch


2. 環境與配置


服務端:elasticsearch-6.2.2 1臺
服務端配置文件:elasticsearch.yml


cluster.name: springboot-es-applicationnetwork.host: 192.168.1.100http.port: 9200

(左右滑動查看全部代碼)


/etc/security/limits.conf


* soft nofile 65536hard nofile 65536


/etc/sysctl.conf


vm.max_map_count=262144


3. 版本


springboot版本:2.1.6.RELEASE
elasticsearch版本:6.2.2


4. maven依賴

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>
<groupId>com.primeton.example</groupId> <artifactId>primeton-elasticsearch-example</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging>
<name>primeton-elasticsearch-example</name> <description></description>
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version>
<elasticsearch.version>6.2.2</elasticsearch.version> <spring.data.elasticsearch.version>3.1.0.RELEASE</spring.data.elasticsearch.version> </properties>
<dependencies> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>${elasticsearch.version}</version> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>transport</artifactId> <version>${elasticsearch.version}</version> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-client</artifactId> <version>${elasticsearch.version}</version> </dependency> <dependency> <groupId>org.elasticsearch.plugin</groupId> <artifactId>transport-netty4-client</artifactId> <version>${elasticsearch.version}</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-elasticsearch</artifactId> <version>${spring.data.elasticsearch.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
</project>

(左右滑動查看全部代碼)


5. application.properties


spring.data.elasticsearch.cluster-name=springboot-es-applicationspring.data.elasticsearch.cluster-nodes=192.168.1.100:9300

(左右滑動查看全部代碼)


看到這裏大家也許會感到疑惑,前面的配置文件端口號明明寫的是9200,這裏爲了要寫成9300呢?


因爲:


9200端口是通過http協議連接es使用的端口;
9300端口是使用tcp客戶端連接使用的端口; 


因此咱們的springboot程序作爲客戶端想要連接elasticsearch就要使用9300端口;


6. 實戰代碼


1. 使用Spring Data Elasticsearch Repositories操作Elasticsearch


首先定義一個商品實體類entity


package com.primeton.example.entity;
import lombok.Data;import org.springframework.data.annotation.Id;import org.springframework.data.elasticsearch.annotations.Document;
import java.io.Serializable;
@Data@Document(indexName = "product")public class Product implements Serializable {
@Id private String productId;
private String name;
private String category;
private Integer price;
private String brand;
private Integer stock;
}

(左右滑動查看全部代碼)


這裏我們創建了一個Product的entity,表示商品的實體類。我們可以看到在Document註解中,只指定了indexName,並沒有指定type,在elasticsearch6.x版本中,不建議使用type,而且在7.X版本中將會徹底廢棄type。這裏,一個Product就代表一個商品,同時也代表了一條索引記錄。


這裏類比關係型數據庫的話,一個索引(Index)就相當於一張表,一個文檔(Document)就相當於一條記錄。


然後我們需要自己定義一個接口,並繼承ElasticsearchRepository。


package com.primeton.example.dao;
import com.primeton.example.entity.Product;import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;import org.springframework.stereotype.Repository;
@Repositorypublic interface ProductRepository extends ElasticsearchRepository<Product, String> {
}

(左右滑動查看全部代碼)


這裏的Repository相當於我們常說的DAO層。


接下來定義service接口


package com.primeton.example.service;
import com.primeton.example.entity.Product;import org.springframework.data.domain.Page;
import java.util.List;
public interface ProductService {
long count();
Product save(Product product);
void delete(Product product);
Iterable<Product> getAll();
List<Product> getByName(String name);
Page<Product> pageQuery(Integer pageNo, Integer pageSize, String kw);
}

(左右滑動查看全部代碼)


定義service實現類


package com.primeton.example.service.impl;
import com.primeton.example.entity.Product;import com.primeton.example.dao.ProductRepository;import com.primeton.example.service.ProductService;import org.elasticsearch.index.query.MatchQueryBuilder;import org.elasticsearch.index.query.QueryBuilders;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageRequest;import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;import org.springframework.data.elasticsearch.core.query.SearchQuery;import org.springframework.stereotype.Service;
import java.util.ArrayList;import java.util.List;
@Servicepublic class ProductServiceImpl implements ProductService {
@Autowired private ProductRepository ProductRepository;

@Override public long count() { return ProductRepository.count(); }
@Override public Product save(Product product) { return ProductRepository.save(product); }
@Override public void delete(Product product) { ProductRepository.delete(product); }
@Override public Iterable<Product> getAll() { return ProductRepository.findAll(); }
@Override public List<Product> getByName(String name) { List<Product> list = new ArrayList<>(); MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder("name", name); Iterable<Product> iterable = ProductRepository.search(matchQueryBuilder); iterable.forEach(e->list.add(e)); return list; }
@Override public Page<Product> pageQuery(Integer pageNo, Integer pageSize, String kw) { SearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(QueryBuilders.matchPhraseQuery("name", kw)) .withPageable(PageRequest.of(pageNo, pageSize)) .build(); return ProductRepository.search(searchQuery); }

}

(左右滑動查看全部代碼)


以上我們展示了對es中數據的增刪改查和分頁查詢操作。


最後,我們寫一個測試類來測試其中的方法


package com.primeton.example;
import com.primeton.example.entity.Product;import com.primeton.example.service.ProductService;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.data.domain.Page;import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)@SpringBootTestpublic class ElasticsearchRepositoriesTests {
@Autowired private ProductService productService;
@Test public void testCount() { System.out.println(ProductService.count()); }
@Test public void testInsert() { Product product = new Product(); product.setProductId("0901009001"); product.setName("奶油夾心麪包(10片裝)"); product.setCategory("101"); product.setPrice(880); product.setBrand("徐福記"); productService.save(product);
product = new Product(); product.setProductId("0901009002"); product.setName("切片面包(10片裝)"); product.setCategory("101"); product.setPrice(680); product.setBrand("巴莉甜甜"); productService.save(product);
product = new Product(); product.setProductId("0901009004"); product.setName("原味吐司850g"); product.setCategory("101"); product.setPrice(720); product.setBrand("採蝶軒"); productService.save(product);
}
@Test public void testDelete() { Product product = new Product(); product.setProductId("0901009002"); productService.delete(product); }
@Test public void testGetAll() { Iterable<Product> iterable = productService.getAll(); iterable.forEach(e->System.out.println(e.toString())); }
@Test public void testGetByName() { List<Product> list = productService.getByName("麪包"); System.out.println(list); }
@Test public void testPage() { Page<Product> page = productService.pageQuery(0, 10, "切片"); System.out.println(page.getTotalPages()); System.out.println(page.getNumber()); System.out.println(page.getContent()); }}

(左右滑動查看全部代碼)


以上,就是使用Spring Data Elasticsearch Repositories 操作Elasticsearch的demo示例。


2. 使用ElasticsearchTemplate操作Elasticsearch


package com.primeton.example;
import com.primeton.example.entity.Product;import org.elasticsearch.index.query.QueryBuilders;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;import org.springframework.data.elasticsearch.core.query.*;import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)@SpringBootTestpublic class ElasticsearchTemplateTest {
@Autowired public ElasticsearchTemplate elasticsearchTemplate;
@Test public void testInsert() { Product product = new Product(); product.setProductId("0901009005"); product.setName("葡萄吐司麪包(10片裝)"); product.setCategory("101"); product.setPrice(560); product.setBrand("採蝶軒");
IndexQuery indexQuery = new IndexQueryBuilder().withObject(product).build(); elasticsearchTemplate.index(indexQuery); }
@Test public void testQuery() { SearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(QueryBuilders.matchQuery("name", "吐司")) .build(); List<Product> list = elasticsearchTemplate.queryForList(searchQuery, Product.class); System.out.println(list); }
}

(左右滑動查看全部代碼)


引入的ElasticsearchTemplate是自動裝配的:



以上,就是使用ElasticsearchTemplate 操作Elasticsearch的demo示例。


6.總結


由於篇幅有限,本篇文章給大家介紹了Elasticsearch的基本概念,Elasticsearch具有哪些功能、特點以及使用場景,Elasticsearch的倒排索引結構、並且我們從實戰的角度將Elasticsearch和Springboot整合到了一起,使其可以成爲一個基礎的搜索服務,給系統中其它的微服務應用提供服務。


Elasticsearch不僅僅是一個搜索引擎,同時它還是一個優秀的分佈式系統,其分佈式架構非常值得我們學習,下一篇文章,將重點討論Elasticsearch的分佈式架構,希望能從其架構中學到一些架構經驗,爲我們自己構建一個分佈式系統提供一些方向。


推薦閱讀


微服務平臺之全鏈路追蹤

微服務平臺之API授權

微服務平臺之網關架構與應用


關於作者西西西西索,現任普元微服務團隊java開發工程師,長期致力於IT技術研究,微服務架構設計和開發等工作。擅長springboot、springcloud、elasticsearch、kafka等技術。先後參加EOS MS5.0GA、EOS PLATFORM 8.1LA、上海公安項目的研發工作。


關於EAWorld:微服務,DevOps,數據治理,移動架構原創技術分享。長按二維碼關注!


本文分享自微信公衆號 - EAWorld(eaworld)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

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