我需要使用全文搜索来获取列中包含单词O'henry
的行
$word = "O'henry";
$sql = "SELECT * FROM mytable WHERE to_tsvector('english', col) @@ to_tsquery(:word) ";
$sth = $db->prepare( $sql );
$sth->execute(
array(":word"=>$word)
);
我有两个问题:
1)该查询匹配包含单词O'henry
的列,但它也匹配包含以下内容的列,例如:"O yes, thierry henry is good sportsman。"
2)如果$word
以引号开始,例如'henry
,我得到了一个错误:syntax error in tsquery: "'henry"
,尽管搜索字符串已经被转义了。
我该如何解决这个问题?
默认英语字典将把您的数据标记为将'
视为一个空格。你可以使用ts_debug
来检查PostgreSQL/tsearch将如何处理你的文本:
psql=# SELECT * FROM ts_debug('english','o''henry');
alias | description | token | dictionaries | dictionary | lexemes
-----------+-----------------+-------+----------------+--------------+---------
asciiword | Word, all ASCII | o | {english_stem} | english_stem | {o}
blank | Space symbols | ' | {} | |
asciiword | Word, all ASCII | henry | {english_stem} | english_stem | {henri}
(3 rows)
从这个输出中可以清楚地看出,如果您想让postgres将o'henry
视为单个单词,您将不得不:
- 创建一个自定义字典来处理带有撇号的单词
- 或在使用
tsvector
和tsquery
之前去掉撇号。
我想说第二个选项是迄今为止最简单的:
$sql = "SELECT * FROM mytable WHERE plainto_tsvector('english', replace(col, '''','')) @@ to_tsquery(replace(:word,'''',''));"
通读文档后,我认为这是to_tsquery
接受的字符串类型的限制。根据本页:
to_tsquery的输入必须已经遵循通用规则tsquery输入
查询输入规则在这里定义。根据给出的示例,引擎将每个输入单词处理成单引号字符串,这些字符串将在输入时中断。作为解决方案,我在这个论坛帖子中发现了一个建议(用户试图正确地转义输入'ksan
:
select *
from items
where to_tsvector(name) @@ to_tsquery(E'['']ksan')
要将此应用于您的情况,您需要使用以下内容预格式化您的输入:
$word = 'E' . str_replace("'", "['']", $word);