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(),它不会使用索引。