2012-07-04 23 views
6

我開發必須執行在一個大表字符串搜索Android應用程序高效的字符串搜索(約500,000項與街道和地點名稱,所以只是每個條目的幾句話)。SQLite的:在大表

CREATE TABLE Elements (elementID INTEGER, type INTEGER, name TEXT, data BLOB) 

請注意,只有20%的條目在「名稱」列中包含字符串。

執行下面的查詢差不多需要2分:

SELECT elementID, name FROM Elements WHERE name LIKE %foo% 

我現在試圖用FTS3爲了加快查詢。這是相當成功的,查詢時間縮短到1分鐘(令人驚訝的數據庫文件大小僅增長了5%,這也是我的目的相當不錯)。

問題是,FTS3貌似不支持子字符串搜索,即如果我想在「foo bar」和「foobar」中找到「bar」,我只會得到「foo bar」,雖然我需要兩個結果。

所以其實我有兩個問題:

  1. 是否有可能進一步加快查詢?我的目標是查詢30秒,但我不知道這是真實的......

  2. 我怎樣才能使用FTS3真正的字符串搜索?

+0

它需要很多*的粉碎來獲得子字索引搜索... – 2012-07-04 20:05:37

+0

也許SQLite/FST不是在這種特定情況下的最佳方法..它似乎是一個[只讀] [後綴樹](http://en.wikipedia.org/wiki/Suffix_tree)可能更合適。雖然訣竅是在現有的合適的庫/工具中找到一個;-) – 2012-07-04 20:13:33

+0

@pst,後綴樹聽起來很酷,但不幸的是,SQLite方法對於我的應用程序的主要功能至關重要。不過,快速搜索字符串會是一件「高興」的事情。 ;) – Aletheios

回答

9

解決方案1: 如果你可以在你的數據庫作爲一個單獨的單詞每個字符,你可以使用phrase queries來搜索子字符串。

例如,假設 「MY_TABLE」 包含一列 「人」:

person 
------ 
John Doe 
Jane Doe 

,你可以把它改成

person 
------ 
J o h n D o e 
J a n e D o e 

要搜索字符串 「翁」,用短語查詢:

SELECT * FROM my_table WHERE person MATCH '"o h n"' 

請注意,「JohnD」將匹配「John Doe」,這可能不是我們想要的。 要修復它,改變原來的字符串空格字符變成別的東西。

例如,你可以用「$」代替空格字符:

person 
------ 
J o h n $ D o e 
J a n e $ D o e 

解決方案2: 繼液1的想法,可以讓每一個字符作爲一個自定義的單詞標記器並使用短語查詢來查詢子字符串。

與解決方案1相比,您不必在數據中添加空格,這可能會不必要地增加數據庫的大小。

缺點是你必須實現自定義標記器。幸運的是,我有one ready for you。代碼以C語言編寫,因此您必須弄清楚如何將它與Java代碼集成。

+0

感謝您的想法;聽起來很有希望。添加所有這些空格可能會炸燬我的數據庫的大小(這不是我想要的),但我會盡快嘗試一下。 – Aletheios

+0

如果大小是您的問題,請檢查解決方案2. –

+0

我已經測試了您的第一個解決方案。正如預期的那樣,數據庫大小几乎翻了一番,但查詢時間在可接受的範圍內(雖然「常規」查詢仍然更快 - 但它們當然也不能提供我需要的所有結果)。我沒有時間將第二個解決方案包含在我的項目中,但我測試了您在GitHub上提供的示例,並且它看起來確實很有前途,因爲它可以保持數據庫大小不變。我想這是速度和結果質量之間的最佳平衡,所以我會將您的答案標記爲正確。 – Aletheios

-1

不知道超速起來,因爲你正在使用sqllite,但對於字符串搜索,我做的事情一樣

SET @foo_bar = 'foo bar' 
SELECT * FROM table WHERE name LIKE '%' + REPLACE(@foo_bar, ' ', '%') + '%' 
當然

有詞「富」這隻能返回記錄在「酒吧」之前。

3

您應該添加一個索引到name列的數據庫,應該大大加快查詢。

我相信SQLite3的支持子字符串匹配,如下所示:

SELECT * FROM Elements WHERE name MATCH '*foo*'; 

http://www.sqlite.org/fts3.html#section_3

+0

我剛剛在Android模擬器中嘗試了你的建議。在FTS3中的子字符串匹配似乎按照您的建議工作,但查詢需要很長時間(我在5分鐘後手動殺死了該應用程序)。不幸的是,「名稱」列上的索引似乎不起作用,查詢時間保持不變。 – Aletheios

+0

如果您的FTS3表中有您不需要運行全文搜索的數據,則可以考慮將其刪除。我自己並沒有這樣做,但是你可以嘗試在桌面上運行一個'optimize'命令,看看它是否能夠加快速度:http://www.sqlite.org/fts3.html#optimize – twaddington

+0

也可以使用'optimize 「現在,表現好一點,但並不多。也許我將不得不徹底重新考慮我的應用程序的搜索功能......我會將您的答案標記爲正確,因爲您的提示可能會幫助其他類似問題的人。 – Aletheios

-1

我正面臨一些與您的問題類似的事情。這裏是我的建議嘗試創建一個翻譯表,將所有的單詞翻譯爲數字。然後搜索數字而不是單詞。

請讓我知道這是否有幫助。

+0

這是一個有趣的想法,但我不明白這可以加速搜索。請注意,我的「名稱」列中的條目可以包含多於一個詞,因此存在將多個數字存儲在一個條目中的問題。而且,對於每個單詞的數字表示,子串搜索是不可能的。 – Aletheios

+0

@Aletheios如何爲每個單詞創建一個新列?並推出所有子世界的可能性。 –

+0

對不起,延遲迴復,我最近忙了。對於多列,我會花費相當多的開銷,因爲每個條目的最大字數是不可預測的。除此之外,我無法想象這會顯着加快搜索速度(每一列都必須獨立搜索)。 – Aletheios