乾貨 | 知識庫全文檢索的最佳實踐
1、題記
這是stackoverflow上一篇精彩的問答。
原文不大好理解,我做了梳理+圖解;
原文是ES早期版本,部分寫法已不適用,所有DSL我在6.X上進行了重寫和驗證;
針對原文內容做了擴充套件。
2、知識庫全文檢索問題丟擲
重新審視一個停滯不前的專案,並尋求建議,對數千個“舊”文件進行現代化改造,
最終期望效果:通過網路訪問這些文件。
文件以各種格式存在,有些已經過時:
- .doc,
- PageMaker,
- 硬拷貝hardcopy (OCR),
- PDF
- ……
很多文件已經被轉化成掃描版的PDF,之前我們認為PDF型別是最終的文件格式,現在看來,我們想聽聽建議(比如:xml是不是更好呢?)
核心需求點:
1、一旦所有文件都採用通用格式,我們希望通過網頁介面提供其內容並提供搜尋服務。
2、我們希望通過搜尋,能夠靈活地只返回整個文件的部分頁面(我相信的Lucene / elasticsearch使這成為可能?!?)
3、如果所有文件是XML是否會更加靈活?
4、如何儲存、在哪裡儲存XML?是直接儲存在資料庫中還是儲存成檔案系統中的檔案?關於文件中的嵌入式影象/圖表呢?
以上,希望得到回覆。
註解:xml只是提問者的當時初步的理解。
3、精彩回覆
我將推薦ElasticSearch,我們先解決這個問題並討論如何實現它:
這有幾個部分:
- 從文件中提取文字以使它們可以索引(indexable),以備檢索;
- 以全文搜尋形式提供此文字;
- 高亮顯示文件片段;
- 知道文件中的哪些段落可用於分頁;
- 返回完整的文件。
ElasticSearch可以提供什麼:
- ElasticSearch(如Solr)使用Tika從各種文件格式中提取文字和元資料;
- Elasticsearch提供了強大的全文搜尋功能。它可以配置為以適當的語言分析每個文件,它可以藉助boost提高某些欄位的權重(例如,標題比內容更重要),ngrams分詞等標準Lucene操作;
- Elasticsearch可以高亮顯示搜尋結果;
- Elasticsearch不知道這些片段在您的文件中出現的位置;
- Elasticsearch可以將原始文件儲存為附件,也可以儲存並返回提取的文字。但它會返回整個文件,而不是一個頁面。
【直譯】您可以將整個文件作為附件傳送到ElasticSearch,並且可以進行全文搜尋。但是關鍵點在於上面的(4)和(5):知道你文件中的位置,並返回文件的某些部分。儲存單個頁面可能足以滿足您的“我在哪裡”的目的,但是您希望將它們分組,以便在搜尋結果中返回文件,即使搜尋關鍵字出現在不同的頁面上。
任務分解:
3.1、索引部分——將文件儲存在ElasticSearch中。
使用Tika(或任何你喜歡的)來從每個文件中提取文字。將其保留為純文字或HTML格式以保留一些格式。
(忘記XML,不需要它)。
每個文件提取元資料:標題,作者,章節,語言,日期等。
將原始文件儲存在您的檔案系統中,並記錄路徑,以便以後可以使用。
在ElasticSearch中,索引包含所有元資料和可能的章節列表的“doc”文件。
將每個頁面索引為“page”文件,其中包含:
- 包含“doc”文件ID的父欄位(請參閱下面的“父子關係”)
- 文字
- 頁碼
- 也許章節標題或編號
- 您想要搜尋的任何元資料
儲存必備——父子文件關係:
通常,在ES(和大多數NoSQL解決方案)中,每個文件/物件都是獨立的 - 沒有真正的關係。
通過建立“doc”和“page”之間的父子關係,ElasticSearch確保子文件(即“頁面”)與父文件(“doc”)儲存在同一分片上。
這使您能夠執行has_child等的查詢方式,它將根據“page”的內容找到最匹配的“doc”。
圖解示例:
二、檢索部分——
現在進行搜尋。
你如何做到這一點取決於你想如何展示你的結果
- 按頁面page分組,
- 按文件doc分組。
通過頁面的結果很容易。
此查詢返回匹配頁面的列表(每個頁面全部返回)以及頁面中高亮顯示的片段列表。
舉例如下:
POST /my_index/page/_search?pretty=1
{
"query" : {
"match" : {
"text" : "interesting keywords"
}
},
"highlight": {
"pre_tags": [
"<span style=\"color:red\">"
],
"post_tags": [
"</span>"
],
"require_field_match": true,
"fields": {
"title": {}
}
}
}
顯示包含文字高亮欄位的“doc”分組有點棘手。 它不能用一個單一的查詢來完成。
一種方法可能是:
第1步:通過對其子(“頁面”)查詢,返回最匹配的父級(“doc”)。
POST /my_index/doc/_search?pretty=1
{
"query": {
"has_child": {
"type": "page",
"query": {
"bool": {
"must": [
{
"match": {
"text": "interesting keywords"
}
},
{
"term": {
"type": "page"
}
},
{
"term": {
"factor": "5"
}
}
]
}
},
"score_mode": "sum"
}
}
}
第2步:從上述查詢中收集“doc”ID 發出新查詢,從匹配的“頁面”文件中獲取片段。
GET /my_index/page/_search?pretty=1
{
"query" : {
"bool" : {
"must":{
"query" : {
"match" : {
"text" : "interesting keywords"
}
}},
"filter" : {
"terms" : {
"doc_id" : [1,2,3]
}
}
}
},
"highlight" : {
"fields" : {
"text" : {}
}
}
}
第3步:在您的應用程式中,將上述查詢的結果按doc分組並顯示出來。
使用第二個查詢的搜尋結果,您已經擁有了可供顯示的頁面的全文。要轉到下一頁,您可以搜尋它:
GET /my_index/page/_search?pretty=1
{
"query" : {
"constant_score" : {
"filter" :
[
{
"term" : {
"doc_id" : 1
}
},
{
"term" : {
"page" : 2
}
}
]
}
},
"size" : 1
}
或者,給“頁面”文件提供一個由 page_num(例如123_2)組成的ID,然後您可以通過如下的檢索獲取該頁面:
curl -XGET'http://127.0.0.1:9200/my_index/page/123_2
3、擴充套件
Tika是一個內容分析工具,自帶全面的parser工具類,能解析基本所有常見格式的檔案,得到檔案的metadata,content等內容,返回格式化資訊。總的來說可以作為一個通用的解析工具。特別對於搜尋引擎的資料抓去和處理步驟有重要意義。
Tika是Apache的Lucene專案下面的子專案,在lucene的應用中可以使用tika獲取大批量文件中的內容來建立索引,非常方便,也很容易使用。
Apache Tika toolkit可以自動檢測各種文件(如word,ppt,xml,csv,ppt等)的型別並抽取文件的元資料和文字內容。
Tika集成了現有的文件解析庫,並提供統一的介面,使針對不同型別的文件進行解析變得更簡單。Tika針對搜尋引擎索引、內容分析、轉化等非常有用。
4、有沒有現成的開源實現呢?
Ambar是一個開源文搜尋引擎,具有自動抓取,OCR識別,標籤分類和即時全文搜尋功能。
Ambar定義了在工作流程中實現全文字文件搜尋的新方法:
- 輕鬆部署Ambar和一個單一的docker-compose檔案
- 通過文件和影象內容執行類似Google的搜尋
- Ambar支援所有流行的文件格式,如果需要的話可以執行OCR
- 標記您的檔案
- 使用簡單的REST
- Api將Ambar整合到您的工作流程中
參考:
2018-06-07 22:43 思於家中床前