在我投资使用 solr 或 lucene 或 sphinx 之前,我想尝试使用 postgresql 全文搜索在我的系统上实现搜索功能。
我想在表格中搜索全国范围内的企业列表。我创建了一个结合了企业名称和城市的 ts 矢量,以便我可以进行“亚特兰大内陆”等搜索。
我还通过使用搜索的通配符功能来实现自动完成功能,方法是将“:”附加到搜索模式并在关键字之间插入“&”,因此搜索模式“outback atl”变成使用 to_tsquery() 转换为查询之前的“outback & atl:”。
这是我目前遇到的问题。 如果搜索模式输入为“ou”,则会返回许多“Outback Steakhouse”记录。 如果搜索模式输入为“out”,则不会返回任何结果。 如果搜索模式输入为“outb”,则会返回许多“Outback Steakhouse”记录。
做了一些调试,我想出了这个:
select ts_rank(to_tsvector('Outback Steakhouse'),to_tsquery('ou:*')) as "ou",
ts_rank(to_tsvector('Outback Steakhouse'),to_tsquery('out:*')) as "out",
ts_rank(to_tsvector('Outback Steakhouse'),to_tsquery('outb:*')) as "outb"
结果如下:
ou out outb
0.0607927 0 0.0607927
我做错了什么?
这是 pg 全文搜索的限制吗?
我可以用我的字典或配置做一些事情来解决这个异常吗?
更新: 我认为“out”可能是一个停用词。
当我运行此调试查询时,我没有得到任何“out”的词位
SELECT * FROM ts_debug('english','out back outback');
alias description token dictionaries dictionary lexemes
asciiword Word all ASCII out {english_stem} english_stem {}
blank Space symbols {}
asciiword Word all ASCII back {english_stem} english_stem {back}
blank Space symbols {}
asciiword Word all ASCII outback {english_stem} english_stem {outback}
现在我问如何修改停用词列表以删除单词?
更新: 这是我当前使用的查询:
select id,name,address,city,state,likes
from view_business_favorite_count
where textsearchable_index_col @@ to_tsquery('simple',$1)
ORDER BY ts_rank(textsearchable_index_col, to_tsquery('simple',$1)) DESC
当我执行查询时(我使用 Strongloop Loopback + Express + Node),我传递模式来替换 $1 参数。该模式(如上所述)将类似于“keyword:”或“keyword1 & keywords2 & ... & keywordsN:”
谢谢
最佳答案
这里的问题是您正在搜索公司名称,正如@Daniel正确指出的那样 - 'english'
字典不会帮助您找到非字典单词的“模糊”匹配,例如“Outback Steakhouse”等;
'simple'
字典
'simple'
字典本身对您也没有帮助,在您的情况下,公司名称仅适用于完全匹配,因为所有单词均未词干。
'simple'
字典+ pg_trgm
但是如果你使用'simple'
字典一起与 pg_trgm
模块 - 它将正是您所需要的,特别是:
- 对于
to_tsvector('simple','<business name>')
您无需担心停用词“hack”,您将得到所有词素的词干; - 使用
similarity()
来自pg_trgm
你将获得最高的“排名” 为了获得最佳匹配,
看看这个:
WITH pg_trgm_test(business_name,search_pattern) AS ( VALUES
('Outback Steakhouse','ou'),
('Outback Steakhouse','out'),
('Outback Steakhouse','outb')
)
SELECT business_name,search_pattern,similarity(business_name,search_pattern)
FROM pg_trgm_test;
结果:
business_name | search_pattern | similarity
--------------------+----------------+------------
Outback Steakhouse | ou | 0.1
Outback Steakhouse | out | 0.15
Outback Steakhouse | outb | 0.2
(3 rows)
订购方式similarity
DESC
你将能够得到你需要的东西。
更新
根据您的情况,有 2 种可能的选择。
选项#1。
只需为 name
创建 trgm 索引view_business_favorite_count
中的专栏 table ;索引定义可能如下:
CREATE INDEX name_trgm_idx ON view_business_favorite_count USING gin (name gin_trgm_ops);
查询看起来像这样:
SELECT
id,
name,
address,
city,
state,
likes,
similarity(name,$1) AS trgm_rank -- similarity score
FROM
view_business_favorite_count
WHERE
name % $1 -- trgm search
ORDER BY trgm_rank DESC;
选项#2。
使用全文搜索,您需要:
- 创建一个单独的表,例如
unnested_business_names
,您将在其中存储 2 列:第一列将保留to_tsvector('simple',name)
中的所有 词位。函数,第二列将有vbfc_id
(FK 为id
from view_business_favorite_count
表); - 添加
trgm
包含词位的列的索引; - 为
unnested_business_names
添加触发器,这将更新或插入或删除view_business_favorite_count
中的新值使所有单词保持最新
关于postgresql - 为什么这个 postgresql 全文搜索查询返回 ts_rank 为 0?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35207579/