簡體   English   中英

快速的字符串搜索

[英]Fast in string search

我有一個問題,我正在尋找一些指導以解決最有效的方法。 我有2億個數據字符串,大小從3個字符到70個字符不等。 字符串由字母數字和一些特殊字符組成,例如破折號和下划線。 我需要能夠快速搜索整個字符串或字符串中的任何子字符串(最小子字符串大小為3)。 快速定義為少於1秒。

作為我的第一個切入點,我做了以下工作:

  1. 創建了38個索引文件。 索引包含以特定字母開頭的所有子字符串。 前4mb包含100萬個哈希桶(哈希鏈的開始)。 索引的其余部分包含來自哈希存儲桶的鏈接列表鏈。 我的哈希非常均勻地分布。 1百萬個哈希存儲桶保留在RAM中並鏡像到磁盤。

  2. 當將字符串添加到索引時,它會分解為非重復的(在其內部)3-n個字符子字符串(當n是字符串-1的長度時)。 因此,例如,“蘋果”以pples,pple,ppl,pp的形式存儲在“ A”索引中(子字符串也存儲在“ L”和“ P”索引中)。

搜索/添加服務器作為守護程序運行(在C ++中),並且像冠軍一樣工作。 典型的搜索時間少於1/2秒。

問題出在流程的前端。 我通常一次添加30,000個密鑰。 該過程的這一部分需要永遠的時間。 通過基准測試,裝入180,000個可變長度鍵的空索引中的加載時間約為3 1/2小時。

除了非常長的加載時間外,此方案都有效。

在我進行優化(或嘗試進行優化)之前,我想知道是否有更好的方法來解決此問題。 對於如此大的數據集,前后通配符搜索(例如:DBMS中的字符串,例如'%ppl%')的速度非常慢(例如,在MySQL中約為小時),因此DBMS解決方案似乎是不可能的。我不能使用全文搜索,因為我們不是在處理普通單詞,而是可能由真實單詞組成的字符串。

根據您的描述,數據加載需要花費所有時間,因為您正在處理I / O,將膨脹的字符串鏡像到硬盤。 這絕對是一個瓶頸,主要取決於您向磁盤讀取和寫入數據的方式。

使用帶有某些LRU策略的mmap可以實現執行時間的改善。 我非常確定復制數據的想法是為了使搜索更快,但是由於您正在使用-似乎只有-一台機器,因此瓶頸將從內存搜索轉移到I / O要求。

您可能不感興趣的另一種解決方案-有趣的是,它也很有趣並且令人不安(:-),將數據拆分到多台計算機上。考慮到數據的結構方式,實現本身可能需要一些時間時間,但這將非常簡單。您將擁有:

  • 每台機器都由一組存儲桶負責,這些存儲桶是使用類似於hash_id(bucket) % num_machines東西選擇的;
  • 插入是從每台機器本地執行的;
  • 搜索可以通過的查詢-應用程序的某種類型進行接口,或者可以簡單地聚集成查詢集-如果應用程序不是交互式的;
  • 考慮到您可能從一個節點發送開始請求,然后將請求轉發到另一個節點(也包括集群請求,以避免過多的I / O開銷),搜索甚至可能具有分布式接口。

如您所說,另一個好處是,數據是均勻分布的-已經\\ o /; 這通常是分布式實現中最挑剔的部分之一。 此外,這將具有很高的可擴展性,因為每當數據大小增加時,您可能會添加另一台計算機。

不用一次完成所有操作,而是要通過38次解決問題。

讀取180,000個字符串中的每個字符串。 在每個字符串中找到“ A”,然后僅將內容寫到“ A”哈希表中。 完成后,將“ A”哈希表的整個完成結果寫到磁盤上。 (有足夠的RAM可以將整個“ A”哈希表存儲在內存中-如果不這樣做,則可以制作較小的哈希表。即,在成對的起始字母上具有38 ^ 2哈希表,並具有1444個不同的表。您可以甚至根據前綴的通用性來動態更改哈希表的鍵號,因此它們的大小都適中。跟蹤此類前綴的時長並不昂貴。)

然后讀取180,000個字符串中的每個字符串,查找“ B”。 等等。

我的理論是,由於海量表緩存的混亂,您的運行速度可能會比平時慢。

下一個可能有用的事情是限制對字符串進行哈希處理的時間,以縮小表的大小。

如果不將長度為70的字符串的所有2278個子字符串的長度設為3到70,則將哈希的長度限制為10個字符,則只有508個子字符串的長度為3到10。而且字符串上可能不會發生太多沖突長度大於10的字符串。您可以再次使哈希的長度是動態的-長度X哈希可能帶有一個標志,表示“如果您的字符串長於X,則嘗試長度X + Y哈希,這太常見了”,否則只需終止哈希即可。 這可能會減少表中的數據量,但在某些情況下會以較慢的查找為代價。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM