使用连字符和数字进行 Postgres 全文搜索
Postgres Full-Text Search with Hyphen and Numerals
我观察到在我看来 Postgres 的 to_tsvector 函数有一个奇怪的行为。
SELECT to_tsvector('english', 'abc-xyz');
returns
'abc':2 'abc-xyz':1 'xyz':3
然而,
SELECT to_tsvector('english', 'abc-001');
returns
'-001':2 'abc':1
为什么不是这样的?
'abc':2 'abc-001':1 '001':3
我应该怎么做才能仅按数字部分进行搜索,而不使用连字符?
文本搜索解析器似乎将连字符后跟数字识别为有符号整数的符号。使用 ts_debug()
:
进行调试
SELECT * FROM ts_debug('english', 'abc-001');
alias | description | token | dictionaries | dictionary | lexemes
-----------+-----------------+-------+--------------+------------+---------
asciiword | Word, all ASCII | abc | {simple} | simple | {abc}
int | Signed integer | -001 | {simple} | simple | {-001}
其他文本搜索配置(例如 'simple' 而不是 'english')将无济于事,因为解析器本身是 "at fault" 这里(值得商榷)。
一个简单的解决方法(除了修改解析器,我从未尝试过)是预处理字符串并将连字符替换为 m-dash (—
) 或只是空白以确保它们是标识为 "Space symbols"。 (实际有符号整数在此过程中会丢失负号。)
SELECT to_tsvector('english', translate('abc-001', '-', '—'))
@@ to_tsquery ('english', '001'); -- true now
db<>fiddle here
这可以通过 PG13 的 dict-int 插件的 absval
选项来规避。参见 the official documentation。
但如果您受困于较早的 PG 版本,这里是查询中“数字或负数”解决方法的通用版本。
select regexp_replace($$'test' & '1':* & '2'$$::tsquery::text,
'''([.\d]+''(:\*)?)', '('' | ''-)', 'g')::tsquery;
这导致:
'test' & ( '1':* | '-1':* ) & ( '2' | '-2' )
它将看起来像正数的词素替换为“数字或负数”类型的子查询。
双转换 ::tsquery::text
只是为了展示如何将转换为文本的 tsquery 传递。
请注意,它也处理前缀匹配数字词素。
我观察到在我看来 Postgres 的 to_tsvector 函数有一个奇怪的行为。
SELECT to_tsvector('english', 'abc-xyz');
returns
'abc':2 'abc-xyz':1 'xyz':3
然而,
SELECT to_tsvector('english', 'abc-001');
returns
'-001':2 'abc':1
为什么不是这样的?
'abc':2 'abc-001':1 '001':3
我应该怎么做才能仅按数字部分进行搜索,而不使用连字符?
文本搜索解析器似乎将连字符后跟数字识别为有符号整数的符号。使用 ts_debug()
:
SELECT * FROM ts_debug('english', 'abc-001');
alias | description | token | dictionaries | dictionary | lexemes
-----------+-----------------+-------+--------------+------------+---------
asciiword | Word, all ASCII | abc | {simple} | simple | {abc}
int | Signed integer | -001 | {simple} | simple | {-001}
其他文本搜索配置(例如 'simple' 而不是 'english')将无济于事,因为解析器本身是 "at fault" 这里(值得商榷)。
一个简单的解决方法(除了修改解析器,我从未尝试过)是预处理字符串并将连字符替换为 m-dash (—
) 或只是空白以确保它们是标识为 "Space symbols"。 (实际有符号整数在此过程中会丢失负号。)
SELECT to_tsvector('english', translate('abc-001', '-', '—'))
@@ to_tsquery ('english', '001'); -- true now
db<>fiddle here
这可以通过 PG13 的 dict-int 插件的 absval
选项来规避。参见 the official documentation。
但如果您受困于较早的 PG 版本,这里是查询中“数字或负数”解决方法的通用版本。
select regexp_replace($$'test' & '1':* & '2'$$::tsquery::text,
'''([.\d]+''(:\*)?)', '('' | ''-)', 'g')::tsquery;
这导致:
'test' & ( '1':* | '-1':* ) & ( '2' | '-2' )
它将看起来像正数的词素替换为“数字或负数”类型的子查询。
双转换 ::tsquery::text
只是为了展示如何将转换为文本的 tsquery 传递。
请注意,它也处理前缀匹配数字词素。