我有一个存储人名的表
CREATE TABLE `person` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`first_name` varchar(100) NOT NULL,
`last_name` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
FULLTEXT KEY `first_name_last_name` (`first_name`,`last_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `person` (`first_name`, `last_name`) VALUES
('Aristide', 'Romano'),
('Jérôme', 'Nadeau'),
('Madeleine', 'Roger'),
('Daniel', 'De Jong'),
('Alban', 'Hervé'),
('Camille', 'Evrard'),
('Delphine', 'Vriaud'),
('Pavel', 'Lelièvre'),
('Albert', 'De Vries'),
('Luc', 'Robin'),
('Vanessa', 'Olivier'),
('Georges', 'De Vries'),
('Delphine', 'Bernard');
注意:这些是随机生成的名字的摘录,而不是真实的人。
当用户搜索“de vr”时,我想返回包含以“de”开头的单词和以“vr”开头的单词的所有行:
真实的表当然要大得多(大约 10,000 行),并且查询会经常使用,这就是为什么我尝试使用全文搜索而不是繁重的
column LIKE "{search}%"
我无法使用全文搜索中的默认“按相关性排序”,因为始终根据用户输入应用自定义 ORDER BY 子句。我需要查询仅返回这些行,因为如果它们在部分匹配中被稀释,我不能指望好的结果会出现在顶部。 根据
MariaDB 文档中的运算符描述,我认为正确的方法是:
SELECT * FROM person
WHERE MATCH (first_name, last_name) AGAINST ('+de*, +vr*' IN BOOLEAN MODE)
ORDER BY last_name, first_name;
*
的意思是“我接受这个词或这样开头的词...”,“+”的意思是“所有结果必须与这个词匹配”。
但是此查询仅返回“Delphine Vriaud”。看来匹配项必须位于不同的列中,从而防止姓氏“De Vries”匹配。如果我从查询中删除
+
符号:
SELECT * FROM person
WHERE MATCH (first_name, last_name) AGAINST ('de*, vr*' IN BOOLEAN MODE)
ORDER BY last_name, first_name;
我得到了包含“de*”或“vr*”的所有行,如预期的那样,其中包括我想要的 3 行和
我不想要的“Delphine Bernard”。 您可以尝试
在这个小提琴上编辑:我后来发现InnoDB变量
innodb_ft_min_token_size定义了全文索引中必须包含的单词的最小长度。该变量的默认值为 3,这意味着“De Vries”或“De Jong”中的“De”一词不在索引中,可以解释结果。 我已在本地 MariaDb 服务器上将值更改为 2 并再次尝试,但结果没有改变。
或
SELECT *
FROM person
WHERE MATCH (first_name, last_name) AGAINST ('de*,+vr*' IN BOOLEAN MODE)
ORDER BY last_name, first_name;