1. 程式人生 > >(轉)ElasticSearch學習

(轉)ElasticSearch學習

(二期)21、全文搜尋引擎Elasticsearch

【課程21】elasticsearch.xmind82.1KB

【課程21】lucene.xmind0.8MB

【課程21】基本用法....api.xmind83.2KB

【課程21預習】全...arch.xmind0.4MB

 

Lucene

為了更深入地理解ElasticSearch的工作原理,特別是索引和查詢這兩個過程,理解Lucene的工作原理至關重要。本質上,ElasticSearch是用Lucene來實現索引的查詢功能的。

 

lucene的最新發布版本(7.5.0)

建立索引概念

 

為了對文件進行索引,Lucene 提供了五個基礎的類,他們分別是 Document, Field, IndexWriter, Analyzer, Directory。下面我們分別介紹一下這五個類的用途:

 

Document

Document 是用來描述文件的,這裡的文件可以指一個 HTML 頁面,一封電子郵件,或者是一個文字檔案。一個 Document 物件由多個 Field 物件組成的。可以把一個 Document 物件想象成資料庫中的一個記錄,而每個 Field 物件就是記錄的一個欄位。

Field

Field 物件是用來描述一個文件的某個屬性的,比如一封電子郵件的標題和內容可以用兩個 Field 物件分別描述。

Analyzer

在一個文件被索引之前,首先需要對文件內容進行分詞處理,這部分工作就是由 Analyzer 來做的。Analyzer 類是一個抽象類,它有多個實現。針對不同的語言和應用需要選擇適合的 Analyzer。Analyzer 把分詞後的內容交給 IndexWriter 來建立索引。

IndexWriter

IndexWriter 是 Lucene 用來建立索引的一個核心的類,他的作用是把一個個的 Document 物件加到索引中來。

Directory

這個類代表了 Lucene 的索引的儲存的位置,這是一個抽象類,它目前有兩個實現,第一個是 FSDirectory,它表示一個儲存在檔案系統中的索引的位置。第二個是 RAMDirectory,它表示一個儲存在記憶體當中的索引的位置。

搜尋文件概念

Lucene 提供了幾個基礎的類來完成這個過程,它們分別是呢 IndexSearcher, Term, Query, TermQuery, Hits. 下面我們分別介紹這幾個類的功能。

 

Query

這是一個抽象類,他有多個實現,比如 TermQuery, BooleanQuery, PrefixQuery. 這個類的目的是把使用者輸入的查詢字串封裝成 Lucene 能夠識別的 Query。

Term

Term 是搜尋的基本單位,一個 Term 物件有兩個 String 型別的域組成。生成一個 Term 物件可以有如下一條語句來完成:Term term = new Term(“fieldName”,”queryWord”); 其中第一個引數代表了要在文件的哪一個 Field 上進行查詢,第二個引數代表了要查詢的關鍵詞。

TermQuery

TermQuery 是抽象類 Query 的一個子類,它同時也是 Lucene 支援的最為基本的一個查詢類。生成一個 TermQuery 物件由如下語句完成: TermQuery termQuery = new TermQuery(new Term(“fieldName”,”queryWord”)); 它的建構函式只接受一個引數,那就是一個 Term 物件。

IndexSearcher

IndexSearcher 是用來在建立好的索引上進行搜尋的。它只能以只讀的方式開啟一個索引,所以可以有多個 IndexSearcher 的例項在一個索引上進行操作。

Hits

Hits 是用來儲存搜尋的結果的。

 

倒排索引

倒排索引(Inverted Index)是一種索引資料結構。在倒排索引中,詞語被對映到包含該詞語的文件。

 

倒排索引源於實際應用中需要根據屬性的值來查詢記錄。

這種索引表中的每一項都包括一個屬性值和具有該屬性值的各記錄的地址。

由於不是由記錄來確定屬性值,而是由屬性值來確定記錄的位置,因而稱為倒排索引(inverted index)。

 

比如:正常關鍵字對應關係應該是:“文章號”對“文章中所有關鍵詞”。倒排索引把這個關係倒過來,變成: “關鍵詞”對“擁有該關鍵詞的所有文章號”。

 

通過使用倒排索引,可以實現快速的全文搜尋。一個簡單的倒排索引及其構建過程如下圖所示,其中文件d1和d2的內容分別是“home sales rise in July”和“increase in home sales in July”。

 

對於文件d1和d2,首先進行分詞處理,將文字內容劃分為詞語集。因為在英文文字中,單詞之間均有空格,所以使用空格作為分隔符進行分詞處理,得到詞語集,如圖中左側一列。對於劃分後的詞語集,進行統計,統計詞語及其出現的次數和位置,如圖中右側一列,構成倒排索引。

 

關鍵詞 文章號[出現頻率] 出現位置   

(倒排索引及其構建過程)

  • 實現時,lucene將上面三列分別作為詞典檔案(Term Dictionary)、頻率檔案(frequencies)、位置檔案 (positions)儲存。其中詞典檔案不僅儲存有每個關鍵詞,還保留了指向頻率檔案和位置檔案的指標,通過指標可以找到該關鍵字的頻率資訊和位置資訊。 
  • 索引時,假設要查詢單詞 “live”,lucene先對詞典二元查詢、找到該詞,通過指向頻率檔案的指標讀出所有文章號,然後返回結果。詞典通常非常小,因而,整個過程的時間是毫秒級的

 

 

專案包分析
  • Package: org.apache.lucene.document

這個包提供了一些為封裝要索引的文件所需要的類,比如 Document, Field。這樣,每一個文件最終被封裝成了一個 Document 物件。

  • Package: org.apache.lucene.analysis

這個包主要功能是對文件進行分詞,因為文件在建立索引之前必須要進行分詞,所以這個包的作用可以看成是為建立索引做準備工作。

  • Package: org.apache.lucene.index

這個包提供了一些類來協助建立索引以及對建立好的索引進行更新。這裡面有兩個基礎的類:IndexWriter 和 IndexReader,其中 IndexWriter 是用來建立索引並新增文件到索引中的,IndexReader 是用來刪除索引中的文件的。

  • Package: org.apache.lucene.search

這個包提供了對在建立好的索引上進行搜尋所需要的類。比如 IndexSearcher 和 Hits, IndexSearcher 定義了在指定的索引上進行搜尋的方法,Hits 用來儲存搜尋得到的結果。

  • org.apache.lucene.queryParser

包含了用於構建、解析查詢條件的類。

  • org.apache.lucene.store包

包含了用於儲存索引的類。

 

時序圖(流程圖)

見程式碼

 

索引與查詢

索引過程:Lucene用使用者指定好的analyzer解析使用者新增的Document。當然Document中不同的Field可以指定不同的analyzer。如果使用者的Document中有title和description兩個Field,那麼這兩個Field可以指定不同的analyzer。

 

搜尋過程:使用者的輸入查詢語句將被選定的查詢解析器(query parser)所解析,生成多個Query物件。當然使用者也可以選擇不解析查詢語句,使查詢語句保留原始的狀態。在ElasticSearch中,有的Query物件會被解析(analyzed),有的不會,比如:字首查詢(prefix query)就不會被解析,精確匹配查詢(match query)就會被解析。對使用者來說,理解這一點至關重要。

 

對於索引過程和搜尋過程的資料解析這一環節,我們需要把握的重點在於:倒排索引中詞應該和查詢語句中的詞正確匹配。

流程
  • Lucene的analysis模組主要負責詞法分析及語言處理而形成Term。
  • Lucene的index模組主要負責索引的建立,裡面有IndexWriter。
  • Lucene的store模組主要負責索引的讀寫。
  • Lucene的QueryParser主要負責語法分析。
  • Lucene的search模組主要負責對索引的搜尋。
  • Lucene的similarity模組主要負責對相關性打分的實現。

在Lucene的倒排索引中,包含欄位(Field)、文件(Document)、關鍵字(Term)這三個部分。每一個關鍵字均與一個集合相對映。集合中的每一個元素為一個二元組(Document,Field),表示該文件的該欄位包含此關鍵字。Lucene的工作原理如圖所示,主要分為以下6個步驟:

  • 1)為每一個待檢索的檔案構建Document類物件,將檔案中各部分內容作為Field類物件。
  • 2)使用Analyzer類實現對文件中的自然語言文字進行分詞處理,並使用IndexWriter類構建索引。
  • 3)使用FSDirectory類設定索引儲存的方式和位置,實現索引的儲存。
  • 4)使用IndexReader類讀取索引。
  • 5)使用Term類表示使用者所查詢的關鍵字以及關鍵字所在的欄位,使用QueryParser類表示使用者的查詢條件。
  • 6)使用IndexSearcher類檢索索引,返回符合查詢條件的Document類物件。
查詢語言

使用者使用Lucene進行查詢操作時,輸入的查詢語句會被分解成一個或者多個Term以及邏輯運算子號。一個Term,在Lucene中可以是一個詞,也可以是一個短語(用雙引號括引來的多個詞)。如果事先設定規則:解析查詢語句,那麼指定的analyzer就會用來處理查詢語句的每個term形成Query物件。

 

一個Query物件中會存在多個布林運算子,這些布林運算子將多個Term關聯起來形成查詢子句。

視覺化工具Luke

(我用這個)

Hibernate Search回顧

回顧之前的課程內容。詳細內容可以回顧之前的課程12的內容、開源部落格專案mblog解讀,其中使用到了Hibernate Search。

通過hibernate search 建立 lucene全文索引。

Hibernate Search是在apache Lucene的基礎上建立的主要用於Hibernate的持久化模型的全文檢索工具。像Lucene這樣的檢索引擎能夠給我們的專案在進行檢索的時候帶來非常高的效率,但是它們在基本物件的檢索時會有一些問題,比如不能實現檢索內容跟實體的轉換,Hibernate Search正是在這樣的情況下發展起來的,基於物件的檢索引擎,能夠很方便的將檢索出來的內容轉換為具體的實體物件。此外Hibernate Search能夠根據需要進行同步或非同步的索引更新。

 

Hibernate Search是 hibernate 對著名的全文檢索系統 Lucene 的一個整合方案,作用在於對資料表中某些內容龐大的欄位(如宣告為text的欄位)建立全文索引,它這樣通過hibernate search就可以對這些欄位進行全文檢索後獲得相應的POJO,從而加快了對內容龐大欄位進行模糊搜尋的速度(sql語句中like匹配)。

原理:

Hibernate Search是給Hibernate持久化模型架構來使用的一套全文檢索工具,其全文檢索依賴於Lucence引擎。全文搜尋引擎(lucence)會將你要查詢的這個欄位的詞語,進行分詞,直接匹配分詞。

執行原理

1、構造LuceneQuery查詢索引庫 

2、EntityManager 構造 FullTextEntityManager 查詢資料庫 

3、合併EntityManager 和 LuceneQuery —– FullTextQuery 查詢索引庫和資料庫 

4、查詢索引庫 fullTextQuery.getResultSize(); 查詢索引,去重id 

5、查詢資料庫 fullTextQuery.getResultList(); 根據索引庫返回 id ,查詢資料庫

Elasticsearch
  • 簡單內容的演示,先做好一個postman的資料演示例子
  • 一個簡單例子(同postman請求例子)
  • 一個複雜例子
簡介

Elasticsearch是一個基於Apache Lucene(TM)的開源搜尋引擎。無論在開源還是專有領域,Lucene可以被認為是迄今為止最先進、效能最好的、功能最全的搜尋引擎庫。

 

但是,Lucene只是一個庫。想要使用它,你必須使用Java來作為開發語言並將其直接整合到你的應用中,更糟糕的是,Lucene非常複雜,你需要深入瞭解檢索的相關知識來理解它是如何工作的。

 

Elasticsearch也使用Java開發並使用Lucene作為其核心來實現所有索引和搜尋的功能,但是它的目的是通過簡單的RESTful API來隱藏Lucene的複雜性,從而讓全文搜尋變得簡單。

基本概念

索引

  • 含有相同屬性的文件集合

文件

  • 文件是可以被索引的基本資料單位

文件型別

  • 索引可以定義一個或多個型別,文件必須屬於一個型別

節點

叢集

分片索引

  • 每個索引都有多個分片,每個分片是一個lucene索引。
  • 由於單個節點由於物理機硬體限制,儲存的文件是有限的,如果一個索引包含海量文件,則不能在單個節點儲存。ES提供分        片機制,同一個索引可以儲存在不同分片(資料容器)中,這些分片又可以儲存在叢集中不同節點上

備份

  • 拷貝一份分片就完成了分片的備份

索引副本

時間之門

 

特點
  • 開箱即用。安裝好ElasticSearch後,所有引數的預設值都自動進行了比較合理的設定,基本不需要額外的調整。包括內建的發現機制(比如Field型別的自動匹配)和自動化引數配置。
  • 天生叢集。ElasticSearch預設工作在叢集模式下。節點都將視為叢集的一部分,而且在啟動的過程中自動連線到叢集中。
  • 自動容錯。ElasticSearch通過P2P網路進行通訊,這種工作方式消除了單點故障。節點自動連線到叢集中的其它機器,自動進行資料交換及以節點之間相互監控。索引分片
  • 擴充套件性強。無論是處理能力和資料容量上都可以通過一種簡單的方式實現擴充套件,即增添新的節點。
  • 近實時搜尋和版本控制。由於ElasticSearch天生支援分散式,所以延遲和不同節點上資料的短暫性不一致無可避免。ElasticSearch通過版本控制(versioning)的機制儘量減少問題的出現。
工作原理 應用場景
  • 海量資料分析引擎
  • 站內搜尋引擎
  • 資料倉庫
安裝

下載linux版本,並解壓。

 

cd elasticsearch-6.4.3
#啟動
./bin/elasticsearch

預設埠9200。

 

  • 單例安裝

root許可權下直接執行elasticsearch會報錯,所以需要切換到其他使用者。

 

#新增一個使用者
useradd lfq
#授權
chown -R lfq /opt/elasticsearch-*
#切換到這個使用者
su lfq

安裝過程中可能會遇到以下兩個錯誤:

1、[1]: max file descriptors [65535] for elasticsearch process is too low, increase to at least [65536]

 

檔案描述符太低

解決辦法:

切換到root使用者修改/etc/security/limits.conf

su root
vim /etc/security/limits.conf

文字末加入

* soft nofile 65536
* hard nofile 131072
* soft nproc 2048
* hard nproc 4096 

推出當前使用者,從新進入

現在ok了~

 

2、[2]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

max_map_count 的值是指一個程序最多可用於的記憶體對映區(memory map areas),在呼叫malloc會用到,由mmap/mprotect生成。

解決辦法:

切換到root使用者修改配置/etc/sysctl.conf

su root
vim /etc/sysctl.conf

加入

vm.max_map_count=655360

然後使其生效

sysctl -p

ok,可以了。

 

3、有時候啟動elasticsearch時候會提示記憶體不足,然後啟動不了,這時候可以改小jvm最小記憶體

cat config/jvm.options
 
  
-Xms1g 改成 -Xms512m

 

如果需要外網訪問,可以新增外網的ip。現在測試環境允許所有人訪問~~

vim config/elasticsearch.yml 
#新增下面一行即可
network.host: 0.0.0.0
#允許跨域訪問,方便後面視覺化工具elasticsearch-head 
http.cors.enabled: true
http.cors.allow-origin: "*"

 

啟動完畢之後,開啟瀏覽器輸入連結:

 

  • 分散式安裝

主節點配置

vim config/elasticsearch.yml
#新增一下配置
cluster.name: kobe
node.name: master
node.master: true

重啟服務。

 

從節點1

從新解壓一份到slave1資料夾

vim config/elasticsearch.yml
 
  
cluster.name: kobe
node.name: slave1
http.port: 9800
network.host: 0.0.0.0
#設定主動發現主節點地址
discovery.zen.ping.unicast.hosts: ["127.0.0.1"]

如果提示id重複,刪除slave1資料夾下的data資料夾下的節點資料,然後重啟即可

 

  • elasticsearch-head安裝

elasticsearch-head 是用於監控 Elasticsearch 狀態的客戶端外掛,包括資料視覺化、執行增刪改查操作等。elasticsearch-head 外掛的安裝在 Linux 和 Windows 沒什麼區別,安裝之前確保當前系統已經安裝 nodejs 即可。

git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
npm install  或者cnpm install(需要安裝淘寶映象)
npm run start
 
  
開啟瀏覽器 http://localhost:9100/

至此,elasticsearch-head連上elasticsearch了。

 

叢集狀態解讀

head外掛會以不同的顏色顯示。 

1. 綠色——最健康的狀態,代表所有的主分片和副本分片都可用; 

2. 黃色——所有的主分片可用,但是部分副本分片不可用; 

3. 紅色——部分主分片不可用。(此時執行查詢部分資料仍然可以查到,遇到這種情況,還是趕快解決比較好。)

 

如果叢集狀態為紅色,Head外掛顯示:叢集健康值red。則說明:至少一個主分片分配失敗。這將導致一些資料以及索引的某些部分不再可用。 

儘管如此, ElasticSearch還是允許我們執行查詢,至於是通知使用者查詢結果可能不完整還是掛起查詢,則由應用構建者來決定。

基本用法-restful api

管理功能

  • i:檢查叢集、節點、索引的狀態以及相關的統計資料
  • ii:管理叢集、節點、索引資料以及源資料

維護索引

  • i:基本操作。 
  • 提供針對索引的CRUD操作(Create【PUT】, Read【GET】, Update【POST】, and Delete【POST】)
  • ii:高階操作 
  • 以及其他如分頁、排序、過濾等高階操作

 

檢查叢集狀態

curl localhost:9200/_cat/health?v

檢查節點狀態

curl localhost:9200/_cat/nodes?v

查詢全部索引

curl localhost:9200/_cat/indices?v

 

適合舊版本的,新版本看postman

https://www.do1618.com/archives/1276/elasticsearch-%E4%B8%AD%E7%9A%84%E7%B4%A2%E5%BC%95%E4%B8%8E%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%89%8D%E7%94%9F%E4%BB%8A%E4%B8%96/

 

建立索引

curl -XPUT localhost:9200/索引名/型別/id -d {//JSON格式的body體}

刪除索引

curl -XDELETE localhost:9200/索引名

查詢索引

curl -XGET localhost:9200/索引名/型別/id
#其中 q=  表示匹配索引中指定資料
curl -XGET localhost:9200/索引名/_search?q=

 

_bulk 批量操作
_search 搜尋
?pretty 表示格式化輸出
  • mapping-結構化對映關係。為空時候是非結構化索引

詳細請看postman~~~,請用postman匯入以下json資料練習!

 

elasticsearch-test.post...tion.json9.9KB

 

高階查詢

簡單查詢

條件查詢

聚合查詢

springboot整合ES

整合配置:

  • 初始化TransportClient
  • InetSocketTransportAddress節點資訊node
  • TransportClient中新增階段資訊,叢集可以新增多個節點。
  • 設定叢集配置Setting,包括cluster.name等資訊

使用:

TransportClient client;

 

專案應用開發指南 開發指南
  • 第一步:索引結構設計

首先需要考慮搜尋的內容主體包含的資訊,如ID,標題、摘要、作者等。還需要包括排序資訊(更新時間,建立時間),或需要搜尋的欄位等資訊。

  • 第二步:為索引結構建立對應的模板(DTO),欄位應該與索引的欄位一一對應。另外,因為key的名字都是定死的,為了統一管理,可以給每個key定義成final,方便統一管理和getset等。
  • 第三步:建立searchService,主要有個兩個方法,1、構建索引(建立、更新),2、刪除索引。
  • 構建索引邏輯:
  • 首先要一個ID作為唯一要構建的索引。通過ID從資料庫中查詢資訊出來,包括需要關聯的表等資訊,得到模板資料(DTO),然後去elasticsearch查詢有沒該索引,如果沒有則建立,如果有一條就更新,如果有多條就全刪除然後重新建立。
  • 考慮到一些elasticsearch有不穩定的時候,所以可以給構建索引、刪除索引建立一個重試機制,比如3次重試機會。
  • 第四步:當業務資料發生變化時候更新對應索引資訊,分為兩種形式呼叫
  • 同步呼叫:直接在業務方法重點呼叫searchService對應的方法。
  • 非同步呼叫:基於訊息中介軟體,如kafka,rabbitmq等。
  • 第五步:編寫搜尋業務。
  • 當用戶沒輸入關鍵字的時候,預設直接從資料庫查詢資訊。
  • 當用戶輸入關鍵字的時候先從elasticsearch條件查詢出資料的IDs,然後拿IDs去從資料庫中取。
複雜查詢
     * 使用QueryBuilder
     * termQuery("key", obj) 完全匹配
     * termsQuery("key", obj1, obj2..)   一次匹配多個值
     * matchQuery("key", Obj) 單個匹配, field不支援萬用字元, 字首具高階特性
     * multiMatchQuery("text", "field1", "field2"..);  匹配多個欄位, field有萬用字元忒行
     * matchAllQuery();         匹配所有檔案
     

 

          * 組合查詢
     * must(QueryBuilders) :   AND
     * mustNot(QueryBuilders): NOT
     * should:                  : OR
 
  

 

  * 只查詢一個id的
     * QueryBuilders.idsQuery(String...type).ids(Collection<String> ids)

 

   /**
     * moreLikeThisQuery: 實現基於內容推薦, 支援實現一句話相似文章查詢
     * {   
        "more_like_this" : {   
        "fields" : ["title", "content"],   // 要匹配的欄位, 不填預設_all
        "like_text" : "text like this one",   // 匹配的文字
        }   
    }     
    
    percent_terms_to_match:匹配項(term)的百分比,預設是0.3
 
  
    min_term_freq:一篇文件中一個詞語至少出現次數,小於這個值的詞將被忽略,預設是2
    
    max_query_terms:一條查詢語句中允許最多查詢詞語的個數,預設是25
    
    stop_words:設定停止詞,匹配時會忽略停止詞
    
    min_doc_freq:一個詞語最少在多少篇文件中出現,小於這個值的詞會將被忽略,預設是無限制
    
    max_doc_freq:一個詞語最多在多少篇文件中出現,大於這個值的詞會將被忽略,預設是無限制
    
    min_word_len:最小的詞語長度,預設是0
    
    max_word_len:最多的詞語長度,預設無限制
    
    boost_terms:設定詞語權重,預設是1
    
    boost:設定查詢權重,預設是1
    
    analyzer:設定使用的分詞器,預設是使用該欄位指定的分詞器
     */

 

/**
     * 字首查詢
     */
    @Test
    public void testPrefixQuery() {
        QueryBuilder queryBuilder =