我的mongo数据库中有书籍集合
{
"title": "Some cool title",
"authors": [ "Author1", "Author2", ... ],
...
}
我想为这些书创建足够智能的搜索引擎。如果用户在搜索输入中键入内容,则会发生以下情况:
然后我用它做了一些魔术,但我需要帮助的是这个 - 当我说关键字匹配标题/作者时,我的意思是它匹配标题/作者中的某些单词或它的前缀。例如,do
会匹配其中包含do
,doing
,double
但不包含ado
或badoo
的任何字符串。
我用谷歌搜索它,这应该是正确的方法:
public function searchBooksByKeywords($keywords) {
array_walk($keywords, function(&$keyword) {
$keyword = preg_quote($keyword, "/");
});
$filter = array(
'$or' => [
[ "title" => new \MongoRegex("/\\b(" . implode('|', $keywords) . ")/i") ],
[ "authors" => new \MongoRegex("/\\b(" . implode('|', $keywords) . ")/i") ],
]
);
$books = $this->database->Books->find($filter);
return \iterator_to_array($books);
}
它不起作用。对于steal
,我仍然得到tea
之类的结果,即它甚至匹配单词中的子字符串,而不仅仅是前缀。我迷失在这里......
BTW,我使用PHP。
编辑:我发现了问题的可能原因。如果在单词内部匹配,搜索后的单词会在某些非ASCII字符(但可能不是全部)之后立即出现,例如我搜索sto
并获得Město & město
的结果,用于{{ 1}}它找到了ste
和Kroatien Dalmatinische Küste
等等。
答案 0 :(得分:2)
我终于找到了解决方案。我只是将u
标志添加到正则表达式。
new \MongoRegex("/\\b(" . implode('|', $keywords) . ")/iu"
PHP文档说
此修饰符打开与Perl不兼容的PCRE的其他功能。模式字符串被视为UTF-8。此修饰符可从Unix上的PHP 4.1.0或更高版本以及win32上的PHP 4.2.3获得。从PHP 4.3.5开始检查模式的UTF-8有效性。
可以找到here。
答案 1 :(得分:1)
试试这个:
new \MongoRegex("/\\b(" . implode('|', $keywords) . ").*\\b/i")
编辑:
正如OP在他的编辑中提到的,上述正则表达式对于包含非ASCII字符的关键字失败,例如关键字sto
匹配Město
& město
,ste
匹配Küste
,等等。
因此,在这种情况下,我修改了正则表达式如下:
new \MongoRegex("/(?:^|\\s)(" . implode('|', $keywords) . ")/i")
正则表达式示例:http://regex101.com/r/nR9lH6
答案 2 :(得分:0)
在查看您的编辑后,很明显您需要增强限制字的边界 它仅限ASCII字符。有很多方法可以做到这一点。
如果搜索字符串/关键字中的第一个字符可能位于\ x80 - \ xff之间,则需要采用完全不同的方法。希望不是这样的。
new \MongoRegex("/(?:^|(?<=[\\x00-\\x7f]))(?=[\\x00-\\x7f])\\b(" . implode('|', $keywords) . ")/i")
# --------------------------------------------
# Using hex
(?: # Group start
^ # Beginning of string
| (?<= [\x00-\x7f] ) # or, ASCII character behind us
) # Group end
(?= [\x00-\x7f] ) # ASCII character in front of us
\b # word boundry
# --------------------------------------------
# Using Posix
(?: # Group start
^ # Beginning of string
| (?<= [[:ascii:]] ) # or, ASCII character behind us
) # Group end
(?= [[:ascii:]] ) # ASCII character in front of us
\b # word boundry