ES相關面試題

海山了-發表於2024-07-10

題目:

  1. 全文搜尋對應的是什麼功能,怎麼構建索引,查詢的時候怎麼查

  2. 怎麼構建倒排索引,使用MySQL可以實現倒排索引的功能嗎

前情提要:

我的專案中的商城專案中存在使用ElasticSearch的情況,所以特地弄了此篇來應對提問,以及還有一個爬蟲專案中也使用到了

question One

全文搜尋對應的是什麼功能,怎麼構建索引,查詢的時候怎麼查?

全文搜尋對應的是商品的搜尋功能,以及廠家的搜尋功能
構建索引這方面其實使用的是ElasticSearch的倒排索引

其中主要涉及的是mappings的構建吧,印象中較為深刻的是構建的時候,首先我們是基於MySQL的資料結構進行構建,其中選取需要在搜尋時,商品方面使用到的資訊例如說商品的名稱,商品的標籤,價格等等,而廠家方面使用到的有廠家名字,以及廠家的描述

其中mappings的建立中,需要注意的是keyword,以及text等
區別在於如果是keyword,那麼只能精準匹配(不會進行分詞),如果是text則會進行分詞,在上述的情況上商品名稱我使用的是text,而標籤使用的是keyword,而對應的廠家名稱使用的是多欄位將欄位同時定義為 keywordtext 型別,以便支援精確匹配和部分匹配
然後值得一提的是,倒排索引嘛,肯定是需要分詞的,而我們中文不能像英文那麼直接根據空格進行分詞,所以我們ES在使用的時候需要額外使用外掛IK分詞器,然後其他的倒是沒太多需要注意的了
在對應的mappings的建立中注意動靜分離,只在ES中儲存要檢索的、修改不頻繁的欄位

然後就是同步上會有一些額外的考慮,例如說如何保持資料一致?
這裡我是在幾種方案中做出了選擇:

  1. 定時任務(例如說一分鐘內進行一次,那麼可能會導致說給db增加 負擔而且相較於cannal,相當於中間加了一層,而且多涉及了兩次IO)
  2. 雙寫(雙寫可能會導致資料的增添會延長響應時間,然後雙寫在使用上還有一個問題就是如果mysql寫入成功,而es寫入失敗的情況,到時候無論是採用重試機制還是說結合定時任務來再次同步或者使用日誌告警等機制,都可能處理上會更加麻煩)
  3. 使用Logstash進行資料同步(查詢了一些網上的情況,發現是一般需要配合kafka和beats採集器,覺得會讓這個專案過於龐大,所以否決了)
  4. 使用Canal進行監聽 BinLog來實時同步(最終採用的是Binlog的機制)

然後最後值得一提的是ES幾乎提供了許多我們搜尋上需要的功能:無論是搜尋高亮還是搜尋建議上

查詢的時候,幾乎就是編寫他對應的語句嘍,其中如果學習的話,編寫sql語句也能執行,不過沒有原生支援的效能好(具體不太清楚,好像是在官方文件看到的),然後就是其中語句編寫的麻煩,我總共試過兩個版本一個8開頭的版本(在當時應該是僅此最新版的版本)(相對而言踩得坑非常多),另一個是使用7.9,其中maven依賴上都變化了很多,但是之後發現他們的api其實是有共性的甚至可以說他們的api就是基於語句的巢狀來編寫的, 之後就容易很多了

Question two

怎麼構建倒排索引,使用MySQL可以實現倒排索引的功能嗎?

倒排索引(Inverted Index)是一種索引資料結構,常用於全文檢索系統和搜尋引擎中。它將文件中的內容和文件本身進行關聯,便於快速查詢包含特定詞彙的文件。

倒排索引的基本概念

  1. 文件(Document):要被搜尋的基本單位,比如一篇文章、一頁網頁等。
  2. 詞彙表(Vocabulary):文件集合中所有唯一詞彙的列表。
  3. 倒排列表(Posting List):每個詞彙對應的文件ID列表,表示哪些文件中包含這個詞彙。

倒排索引的結構

假設有以下三個文件:

  • Doc1: "The quick brown fox"
  • Doc2: "The quick blue fox"
  • Doc3: "The lazy dog"

倒排索引可能會是這樣:

Term Posting List
The Doc1, Doc2, Doc3
quick Doc1, Doc2
brown Doc1
fox Doc1, Doc2
blue Doc2
lazy Doc3
dog Doc3

倒排索引的構建步驟

  1. 詞項提取:從每個文件中提取詞彙。(例如說中文中需要涉及的IK分詞器)
  2. 詞項標準化:將詞項進行標準化處理,如大小寫轉換、詞幹提取等。
  3. 建立詞彙表:構建所有詞項的詞彙表。
  4. 建立倒排列表:將詞項與包含該詞項的文件ID進行關聯。

倒排索引的優點

  • 查詢效率高:可以快速定位包含查詢詞的所有文件。
  • 空間利用率高:相較於其他索引方法,倒排索引的儲存需求較少。

使用場景

  • 搜尋引擎:如Google、Elasticsearch等。
  • 全文檢索系統:用於大規模文字資料的快速搜尋和分析。
  • 資料庫系統:用於文字欄位的高效檢索。
使用MySQL可以實現倒排索引的功能嗎?

MySQL有個同樣能實現相關全文搜尋功能的索引,也就是全文索引

其中底層不少就用到了倒排索引的功能,我們也可以自己實現,畢竟MySQL底層應該也是同樣的對於中文的分詞同樣會有問題

MySQL 中的全文索引(Full-Text Index)用於對文字資料進行高效的全文搜尋。全文索引允許你在表的一個或多個文字列上建立索引,從而加快包含大量文字資料的列的搜尋速度。它主要用於在大文字欄位中查詢特定的單詞或短語,而不是簡單的字首匹配或完整匹配。

全文索引的作用
  1. 高效全文搜尋:全文索引使得對大文字資料的搜尋更加高效,尤其是在搜尋單詞或短語時。使用全文索引的搜尋速度比對大文字欄位進行 LIKE 搜尋要快得多。
  2. 自然語言搜尋:支援自然語言搜尋,允許按相關性對結果進行排序。
  3. 布林模式搜尋:支援布林模式搜尋,可以使用布林運算子(如 AND, OR, NOT)來構造複雜的查詢。
底層資料結構

在 MySQL 中,全文索引的底層資料結構依賴於儲存引擎:

MyISAM 儲存引擎

MyISAM 使用倒排索引(Inverted Index)來實現全文搜尋。倒排索引類似於一個字典,詞彙對映到文件 ID 列表,允許快速查詢包含特定詞彙的所有文件。

InnoDB 儲存引擎

InnoDB 的全文索引實現更加複雜,因為 InnoDB 的底層資料結構是 B+ 樹,而不是 MyISAM 的倒排索引。為了支援全文搜尋,InnoDB 使用了一種特殊的資料結構和處理方法。

  • 分詞:首先將文字資料分成詞項(terms)。
  • 倒排索引表:建立一個內部的倒排索引表,將詞項對映到文件 ID 列表中。
  • 輔助表:使用輔助表儲存後設資料和其他必要的資訊,以支援高效的全文搜尋。

具體實現上,InnoDB 可能會使用一種類似於倒排索引的資料結構來儲存詞項和文件 ID 的關係,同時利用 InnoDB 本身的事務和併發處理能力,確保全文索引的效能和可靠性。

全文索引與 B+ 樹的區別
  • B+ 樹:主要用於儲存和索引有序資料,適合範圍查詢和排序。每個節點包含一個有序的鍵值列表,葉節點儲存資料的實際指標。
  • 倒排索引:主要用於文字搜尋,適合查詢包含特定詞彙的文件。倒排索引包含詞彙到文件 ID 的對映,允許快速查詢包含特定詞彙的所有文件。
InnoDB 中的全文索引

為了支援全文索引,InnoDB 做了以下調整:

  1. 分詞處理:在插入或更新時,對文字進行分詞,將其拆分為單獨的詞項。
  2. 倒排索引:為每個詞項建立一個倒排索引,儲存詞項和文件 ID 的對映。
  3. 輔助資料結構:使用輔助表和資料結構,儲存必要的後設資料和統計資訊,以支援高效查詢和排序。

自己的題目:既然Mysql有倒排索引為什麼你還要使用ES呢?

題目來源

盒馬 暑期實習 Java 一面涼經_牛客網 (nowcoder.com)

相關文章