在JAVA中將Elasticsearch索引載入到Lucene API
每隔一段時間,Elasticsearch中就會出現意外(或無意)崩潰。對於我的情況,在Elasticsearch的大量IO操作期間是硬體故障(讓我們假設我沒有任何副本或者我設法使所有叢集崩潰)。經過一些研究,我發現它搞砸了許多索引的狀態檔案(已損壞!)。我想,如果Elasticsearch使用Lucene,我肯定可以載入我的資料並使用Lucene API重新索引它。
重要說明:要使本指南處理索引,必須在對映中啟用_source欄位的索引。如果您因任何原因禁用了_source欄位,則此程式碼將不適用於您的索引。lasticsearch建議始終啟用它。
在我們開始之前,讓我們引用兩個重要的術語。更多細節可以在這裡找到。
- 索引:用於在Elasticsearch中儲存資料的位置。
- Shard分片或Lucene索引例項(!):每個索引由一個或多個分片組成。它是一個獨立的搜尋引擎,可以索引和處理Elasticsearch叢集中資料子集的查詢。
正如你在這裡看到,我們的資料駐留在索引和這些分佈到多個分片,後者實際上是一個Lucene索引 !
讓我們看一下Elasticsearch資料的結構,並嘗試找到這些Lucene索引。您可以配置資料路徑elasticsearch.yml與關鍵path.data。
索引indices目錄下有一個名為類似eCCAJ-x6SOuN6w7vqr4tGQ格式的資料夾。(這些專案的說明是完全獨立的主題。為了簡單起見,只需要知道狀態檔案是由Elasticsearch生成的,它是一個SMILE-encode檔案,其中包含Elasticsearch元資料,如索引名稱,節點ID等。您可以使用十六進位制編輯器來檢查檔案)
讓我們通過Curl我們的Elasticsearch例項來列出我們的索引。
$ curl elastic-host:9200/_cat/indices
yellow open bad_ip eCCAJ-x6SOuN6w7vqr4tGQ 5 1 4609 0 1.2mb 1.2mb
這是我的索引,其中索引了一些惡意IP資料。我們來看看那個目錄。
$ ls my-elasticsearch/data/nodes/0/indices/eCCAJ-x6SOuN6w7vqr4tGQ
0 1 2 3 4 _state
這是我們索引的分片,或者是我們要載入的Lucene索引例項。
提示:如果此時Elasticsearch例項崩潰,您只需在狀態檔案上執行cat命令即可檢視它們所屬的索引。所有檔案都不可讀,但至少你應該看到你的索引名稱。
重要說明#2:在繼續執行程式碼之前,您應該確保您的Lucene索引沒有損壞。為了檢查和修復您的Lucene索引(或Elasticsearch分片),我強烈建議您使用CheckIndex工具。
現在,我們找到了Lucene索引,讓我們做一些編碼來拯救我們的資料。我將建立一個示例Maven專案。這是我們需要的依賴項:
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>7.5.0</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>7.5.0</version>
</dependency>
重要提示#3:您應該檢視您的Elasticsearch例項的Lucene版本,並在此處使用相同的Lucene API版本。執行該命令curl elastic-host:9200 並查詢lucene_version金鑰。
為了簡單起見,我將在main方法中編寫所有程式碼並丟擲異常。這取決於您如何構建程式碼。
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
public class Main {
public static void main(String[] args) throws IOException {
String luceneIndexPath = "my-elasticsearch/data/nodes/0/indices/eCCAJ-x6SOuN6w7vqr4tGQ/0/index";
Directory index = FSDirectory.open(Paths.get(luceneIndexPath));
IndexReader reader = DirectoryReader.open(index);
System.out.println(reader.maxDoc());
reader.close();
index.close();
}
}
執行它,你會看到你的分片檔案的數量。就我而言,我的第0個碎片中有952個文件。如果列出所有主分片並對其進行總結,則它將等於您的Elasticsearch索引中的總文件數。
Directory類來自Lucene API,但它與Java i / o庫沒有太大區別。它只是為了簡化不同來源的實現,例如儲存在資料庫中的索引。我的索引的實際例項是 MMapDirectory。如果您有不同的配置,可能會有所不同。(同樣,這是另一個話題。)
IndexReader是一個用於訪問索引的視點的抽象類。
我們可以使用我們的reader變數訪問大量資訊,例如段資訊和文件本身。我們想要的是找到這些檔案。讓我們編寫那部分程式碼。
for(int i = 0; i < reader.maxDoc(); i++){
if(((DirectoryReader) reader).isCurrent()){
Document document = reader.document(i);
String source = document.getBinaryValue("_source").utf8ToString();
System.out.println(source);
}
}
我們所做的是一個簡單的迴圈並獲得該位置的相應文件。之後,我們只獲取JSON所在的_source鍵。它以二進位制形式儲存,因此,首先我們需要獲取二進位制值,然後進行utf8ToString轉換。
歡迎大家加入粉絲群:963944895,群內免費分享Spring框架、Mybatis框架SpringBoot框架、SpringMVC框架、SpringCloud微服務、Dubbo框架、Redis快取、RabbitMq訊息、JVM調優、Tomcat容器、MySQL資料庫教學視訊及架構學習思維導圖