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