2

在我投资使用 solr 或 lucene 或 sphinx 之前,我想尝试使用 postgresql 全文搜索在我的系统上实现搜索功能。

我的表格中有一个全国性的企业列表,我想搜索。我创建了一个结合了企业名称和城市的 ts 向量,这样我就可以进行像“outback atlanta”这样的搜索。

我还通过使用搜索的通配符功能来实现自动完成功能,方法是将“:”附加到搜索模式并在关键字之间插入“&”,因此搜索模式“outback atl”变成了“outback & atl: " 在使用 to_tsquery() 转换为查询之前。

这是我目前遇到的问题。如果搜索模式输入为“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 & keyword2 & ... & keywordN:

谢谢

4

1 回答 1

2

这里的问题是您正在搜索企业名称,正如@Daniel 正确指出的那样 -'english'字典不会帮助您找到“内陆牛排馆”等非字典单词的“模糊”匹配;

'simple'字典

'simple'字典本身对您也无济于事,在您的情况下,企业名称仅适用于完全匹配,因为所有单词都没有词干。

'simple'字典 +pg_trgm

但是,如果您将'simple'字典 pg_trgm模块一起使用 - 这正是您所需要的,特别是:

  • 因为to_tsvector('simple','<business name>')你不需要担心停用词“hack”,你会得到所有的词素;
  • 使用similarity()from pg_trgmyou 将获得最佳匹配的最高“等级”,

看这个:

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将能够得到您需要的东西。

更新

对于您的情况,有两种可能的选择。

选项1。

name只需为表中的列创建 trgm 索引view_business_favorite_count;索引定义可能如下:

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 列:第 1 列将保留函数中的所有词位to_tsvector('simple',name),第 2 列将具有vbfc_idid from view_business_favorite_count表的 FK);
  • trgm为包含词位的列添加索引;
  • 添加触发器unnested_business_names,它将更新或插入或删除新值,view_business_favorite_count以使所有单词保持最新
于 2016-02-04T19:46:23.120 回答