lucene快速入门_为Lucene选择快速唯一标识符(UUID)
lucene快速入門
大多數使用Apache Lucene的搜索應用程序都會為每個索引文檔分配一個唯一的ID(即主鍵)。 盡管Lucene本身不需要這樣做(它可能不太在乎!),但應用程序通常需要它以后通過其外部ID替換,刪除或檢索該文檔。 大多數在Lucene之上構建的服務器,例如Elasticsearch和Solr ,都需要一個唯一的ID,如果不提供它,則可以自動生成一個ID。
有時,您的ID值已經預先定義,例如,如果外部數據庫或內容管理系統分配了ID ,或者您必須使用URI ,但是如果您可以自由分配自己的ID,那么哪種方法最適合Lucene?
一個明顯的選擇是Java的UUID類,該類生成版本4的通用唯一標識符 ,但事實證明,這是性能上最糟糕的選擇:它比最快的速度慢4倍。 要了解原因,需要對Lucene如何找到術語有所了解。
BlockTree術語詞典
術語詞典的目的是存儲在索引期間看到的所有唯一術語,并將每個術語映射到其元數據( docFreq , totalTermFreq等 )以及totalTermFreq (文檔,偏移量,投遞和有效載荷)。 當請求一個術語時,術語詞典必須在磁盤索引中找到它并返回其元數據。
默認編解碼器使用BlockTree術語詞典 ,該詞典以排序的二進制順序存儲每個字段的所有術語,并將這些術語分配到共享公共前綴的塊中。 默認情況下,每個塊包含25到48個詞。 它使用內存中的前綴三叉戟索引結構( FST )將每個前綴快速映射到相應的磁盤塊,并在查找時首先根據請求的術語的前綴檢查索引,然后在-disk塊并掃描以查找術語。
在某些情況下,當段中的術語具有可預測的模式時,術語索引可以知道請求的術語不能存在于磁盤上。 這種快速匹配測試可以帶來可觀的性能提升,尤其是當索引很冷(操作系統的IO緩存不緩存頁面)時,因為它避免了昂貴的磁盤搜尋。 由于Lucene是基于段的,因此單個id查找必須訪問每個段直到找到匹配項,因此快速排除一個或多個段可能是一個大勝利。 確保您的細分受眾群計數盡可能低也很重要!
鑒于此,完全隨機的id(例如UUID V4 )應該表現最差,因為它們擊敗了術語索引快速匹配測試,并且需要對每個段進行磁盤搜索。 具有可預測的每段模式的ID(例如順序分配的值或時間戳)應發揮最佳作用,因為它們將使術語索引快速匹配測試的收益最大化。
測試性能
我創建了一個簡單的性能測試器來驗證這一點。 完整的源代碼在這里 。 該測試首先將1億個ID索引到具有7/7/8段結構(7個大段,7個中段,8個小段)的索引中,然后搜索200萬個ID的隨機子集,記錄最佳時間5次運行。 我在Ubuntu 14.04上使用Java 1.7.0_55,以及3.5 GHz Ivy Bridge Core i7 3770K。
由于Lucene的術語從4.0開始是完全二進制的 ,因此存儲任何值的最緊湊的方法是二進制形式,其中每個字節使用所有256個值。 然后,一個128位ID值需要16個字節。
我測試了以下標識符來源:
- 順序ID(0、1、2,...),采用二進制編碼。
- 零填充的順序ID(00000000、00000001等),采用二進制編碼。
- 納米時間,二進制編碼。 但是請記住, 納米時間是棘手的 。
- 使用此實現從時間戳,nodeID和序列計數器派生的UUID V1 。
- UUID V4 ,使用Java的UUID.randomUUID()隨機生成。
- 片狀ID ,使用此實現 。
對于UUID和Flake ID,除了標準(16或36基)編碼之外,我還測試了二進制編碼。 請注意,我僅使用一個線程測試了查找速度,但是在添加線程時,結果應該線性擴展(在足夠并行的硬件上)。
以二進制編碼的零填充順序ID最快,比非零填充順序ID快很多。 UUID V4(使用Java的UUID.randomUUID() )慢了約4倍。
但是對于大多數應用程序來說,順序編號是不實際的。 第二快的是UUID V1 ,以二進制編碼。 令我驚訝的是,這比Flake ID快得多,因為Flake ID使用相同的原始信息源(時間,節點ID,序列),但是以不同的方式隨機排列位以保留總順序。 我懷疑問題是在獲取不同文檔之間的數字之前,必須在Flake ID中遍歷的通用前導數字的數目,因為64位時間戳的高位在前,而UUID V1則在低位位首先是64位時間戳。 當一個字段中的所有術語共享一個公共前綴時,術語索引也許可以優化這種情況。
我還分別測試了10、16、36、64、256的基數,通常對于非隨機ID,較高的基數更快。 我對此感到驚訝,因為我希望與BlockTree塊大小(25到48)匹配的基數最好。
此測試有一些重要警告(歡迎補丁)! 一個真正的應用程序顯然比簡單地查找id還要做更多的工作,并且結果可能會有所不同,因為熱點必須編譯更多活動的代碼。 在我的測試中,該索引非常熱(有大量RAM可以容納整個索引); 對于冷索引,我希望結果會更加鮮明,因為避免磁盤搜索變得非常重要。 在實際應用中,使用時間戳的id在時間上會更加分散; 我可以通過偽造更大范圍的時間戳來“模擬”自己。 也許這會縮小UUID V1和Flake ID之間的差距? 我在索引編制過程中僅使用了一個線程,但是具有多個索引編制線程的實際應用程序會將ID一次分散到多個段中。
我使用了Lucene的默認TieredMergePolicy ,但是有一種更聰明的合并策略可能會支持合并ID更“相似”的段,從而可能會產生更好的結果。 該測試不會執行任何刪除/更新操作,這將需要更多的查找工作,因為給定的ID(如果已更新)可能位于多個段中(只是刪除了其中的一個)。
最后,我使用了Lucene的默認編解碼器,但是當您愿意將RAM換成更快的查詢時,我們有不錯的主播查詢格式已優化過,例如去年的Google夏季代碼項目和MemoryPostingsFormat 。 這些可能會帶來可觀的性能提升!
翻譯自: https://www.javacodegeeks.com/2014/05/choosing-a-fast-unique-identifier-uuid-for-lucene.html
lucene快速入門
總結
以上是生活随笔為你收集整理的lucene快速入门_为Lucene选择快速唯一标识符(UUID)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: eduroam电脑可以连接吗(eduro
- 下一篇: 安卓摄像头驱动apk(安卓摄像头驱动)