在Rails应用程序中使用全文postgresql搜索的奇怪行为

时间:2012-08-18 23:28:45

标签: ruby-on-rails ruby-on-rails-3 postgresql full-text-search pg

我跟随Full-Text Search in PostgreSQL Railscast,但我得到了一些奇怪的行为。

例如,当我搜索“警察”时,我没有得到任何结果,但是当我搜索“polic”时,我会这样做。 (警察存在于我正在搜索的内容中)。它根本没有返回一些结果 - 但我知道这个词存在,无论这个词是大还是小。

当我启动rails dbconsole时,它说我正在使用psql(9.1.4),并且应用程序的其余部分似乎也正常运行。

我是否需要重建索引或其他内容?

我正在使用PG gem和postgres_ext gem,我没有使用texticle或pg_search gems(因为我不需要添加的功能)。

我的代码与截屏视频相同:

def self.text_search(query)
  if query.present?
    rank = "ts_rank(to_tsvector(name), plainto_tsquery(#{sanitize(query)}))"
    where("to_tsvector('english', name) @@ :q 
           or to_tsvector('english', content) @@ :q", q: query).order("#{rank} desc")
  else
    scoped
  end
end

我已经创建了索引:

class AddSearchIndexToArticles < ActiveRecord::Migration
  def up
    execute "create index articles_name on articles using gin(to_tsvector('english', name))"
    execute "create index articles_content on articles using gin(to_tsvector('english', content))"
  end
end

有趣的是,如果我在where调用中删除对to_tsvector的调用:

def self.text_search(query)
  if query.present?
    rank = "ts_rank(to_tsvector(name), plainto_tsquery(#{sanitize(query)}))"
    where("name @@ :q 
           or content @@ :q", q: query).order("#{rank} desc")
  else
    scoped
  end
end

...它按预期工作(除了因为索引似乎被忽略而非常慢)

任何想法发生了什么?

更新

在打开完整日志记录后,这是运行的sql:

LOG:  statement: SELECT 1
LOG:  statement: SELECT  "dogs".* FROM "dogs"  WHERE (to_tsvector('english', name) @@ 'wary' 
               or to_tsvector('english', other_names) @@ 'wary'
               or to_tsvector('english', origin) @@ 'wary'
               or to_tsvector('english', kusa) @@ 'wary') ORDER BY         ts_rank(to_tsvector(name), plainto_tsquery('wary'))
     desc LIMIT 10 OFFSET 0
LOG:  statement: SELECT 1
LOG:  statement: SELECT 1

我不是sql专家,但查询看起来不错?

另外,我不确定它是否相关,但日志文件中还有很多这些:

FATAL:  lock file "postmaster.pid" already exists
HINT:  Is another postmaster (PID 821) running in data directory "/usr/local/var/postgres"?

我通过自制软件安装postgres,并使用9.1.4

1 个答案:

答案 0 :(得分:4)

考虑{em>警察这个词是如何被to_tsvector转换的:

select to_tsvector('english','police');

结果:

 to_tsvector 
-------------
 'polic':1

如果我们直接与警察进行比较,那就不会匹配:

select to_tsvector('english','police') @@ 'police' as match;

结果:

 match
----------
 f

(f是此上下文中的布尔 false )。

但如果与plainto_tsquery的结果进行比较,那么它确实匹配:

select to_tsvector('english','police') @@ plainto_tsquery('english','police')  as match;

结果:

 match 
-------
 t

结论:不要将tsvector直接与单词匹配,将其与plainto_tsqueryto_tsquery的结果匹配。


还有一些你可能想要收紧的东西:目前你的查询包含两个to_tsvector调用,其中 english 配置显式传递给它,而调用没有这个参数(在{ {1}}子句,在这种情况下,它默认为ORDER BY参数的当前值。 如果此参数与 english 不同,则可能会在某些表达式中产生意外结果。最好是始终传递此参数,或者始终忽略它。后一种情况具有简洁的优点,并避免对特定语言进行硬编码。