0

我使用Rails 3爲自己和我的朋友構建了一個論壇(由於各種原因,我沒有使用一個開箱即用的論壇),而且我處於我正在嘗試爲論壇實施全文搜索。沒有什麼奇特的 - 只要有人搜索字符串「早上」,我希望能夠顯示所有論壇主題的列表,其中包含單詞「morning」的帖子。我一直在使用pg_search進行搜索,但速度很慢(5秒以上),因爲我們已經在300個論壇帖子中發佈了200k +帖子,其中一些帖子只有4k +個字符。所以我有這個遷移multisearch:使用pg_search和GIN爲大文檔編制索引

class CreatePgSearchDocuments < ActiveRecord::Migration 
    def self.up 
    say_with_time("Creating table for pg_search multisearch") do 
     create_table :pg_search_documents do |t| 
     t.text :content 
     t.belongs_to :searchable, :polymorphic => true, :index => true 
     t.timestamps null: false 
     end 
     add_index :pg_search_documents, :content, using: "gin" 
     PgSearch::Multisearch.rebuild(Post) 
     PgSearch::Multisearch.rebuild(Reply) 
    end 
    end 
end 

但是當我運行與此錯誤遷移它的失敗:

PG::ProgramLimitExceeded: ERROR: index row size 3080 exceeds maximum 2712 for index "index_pg_search_documents_on_content" 
HINT: Values larger than 1/3 of a buffer page cannot be indexed. 
Consider a function index of an MD5 hash of the value, or use full text indexing. 

到目前爲止,谷歌搜索已經得到了我如下:

  • 對於處理100,000個以上的詞位,GIN索引要優於GIST索引。這意味着,我認爲GIN指標應該能夠處理那些只有700字

  • 我有一個猜想,這個錯誤是關於一個單個值而非文件的長度,以及擔心職位這是由於我在論壇帖子中允許使用HTML標籤的一個子集,所以不是存儲post.content,而是存儲post.sanitized_content。這將去除所有HTML,然後用空格替換標點符號,然後去除重複項,如下所示:ActionView::Base.full_sanitizer.sanitize(content).gsub(/[^\w ]/, ' ').squeeze(" ")。這得到了錯誤信息下降到index row size 2848 exceeds maximum 2712,所以它顯然做東西,但還不夠。

  • 然後我理智地檢查了pg_search實際上允許我使用這樣的動態方法,而且它不僅僅是暗中失敗。根據文檔,「但是,如果你在以下情況下調用任何動態方法,將使用以下策略」,因此它們似乎處理得很好。

有關我實施後的碎片:

class Post < ActiveRecord::Base 
    include PgSearch 

    multisearchable against: [:subject, :sanitized_content] 

    def sanitized_content 
    ActionView::Base.full_sanitizer.sanitize(content).gsub(/[^\w ]/, ' ').squeeze(" ") 
    end 
end 

(我也試着刪除:從multisearchable-反序列主題,在情況下,它是一個unsanitized主題導致的問題;這讓我下降到row size 2800的錯誤,但沒有解決它。)

所以...我錯過了什麼? GIN索引不能處理大型文本文檔嗎?我是否需要首先將文檔轉換爲tsvectors,如this answer?它不斷提示「全文索引」,但我認爲這就是這樣。

回答

0

對於未來的谷歌搜索的人的緣故:試探性地使用

execute "CREATE INDEX idx_fts_search_content ON pg_search_documents USING gin(to_tsvector('english', content)) 

代替

add_index :pg_search_documents, :content, using: "gin" 

已經固定它。索引到目前爲止並沒有太大的進步,搜索一切都需要很長的8.1s,但至少現在的遷移已經開始了!

編輯:錯過了一件重要的事情。實際的命令應該是:

execute "CREATE INDEX idx_fts_post_content ON posts USING gin(to_tsvector('english', coalesce(\"posts\".\"content\"::text, '')))" 

如果你沒有coalesce(),它不會使用索引。