【问题标题】:How do I get different scores for partially matching single-word searches on an InnoDB full text index?如何在 InnoDB 全文索引上获得部分匹配的单词搜索的不同分数?
【发布时间】:2018-01-16 15:14:18
【问题描述】:

我在带有 InnoDB 全文索引的 MySQL 5.6 中有下表。

CREATE TABLE `blacklist_entries` (
  `blacklist_entry_id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `insertat` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`blacklist_entry_id`),
  FULLTEXT KEY `ftk_b_n` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=660004 DEFAULT CHARSET=utf8

这是我们正在处理的数据。 name 中的所有条目都是单个单词,有时带有-,但不会超过一个单词。

mysql> select * from blacklist_entries where name like '%battle%';
+--------------------+---------------------+---------------------+
| blacklist_entry_id | name                | insertat            |
+--------------------+---------------------+---------------------+
|               4159 | battleground        | 2018-01-16 12:15:46 |
|             604218 | battle              | 2018-01-16 12:18:59 |
|             604219 | battlefield         | 2018-01-16 12:18:59 |
|             604220 | battlefields        | 2018-01-16 12:18:59 |
|             604221 | battles             | 2018-01-16 12:18:59 |
|             660003 | abcbattle           | 2018-01-16 12:49:34 |
+--------------------+---------------------+---------------------+

我想创建一个全文搜索此列表,该列表能够按相关性排序,其中完全匹配的得分高于部分匹配。

当我运行这个查询时

select
    *,match(name) against ('battle battle* *battle' IN BOOLEAN MODE) as score
from blacklist_entries where match(name)
    against ('battle battle* *battle' IN BOOLEAN MODE);

我得到以下结果。

+--------+---------------------+---------------------+--------------------+
|     id | name                | insertat            | score              |
+--------+---------------------+---------------------+--------------------+
|   4159 | battleground        | 2018-01-16 12:15:46 |  17.11724281311035 |
| 604218 | battle              | 2018-01-16 12:18:59 |  17.11724281311035 |
| 604219 | battlefield         | 2018-01-16 12:18:59 |  17.11724281311035 |
| 604220 | battlefields        | 2018-01-16 12:18:59 |  17.11724281311035 |
| 604221 | battles             | 2018-01-16 12:18:59 |  17.11724281311035 |
+--------+---------------------+---------------------+--------------------+

这有两个问题。

  • 所有结果都有相同的分数,甚至完全匹配
  • 从右不匹配,缺少这一行

    | 660003 | abcbattle           | 2018-01-16 12:49:34 |  17.11724281311035 |
    

我可以更改查询中的某些内容以说服 MySQL 对这些匹配项进行不同的评分吗?

如果这不可能,是否有可行的替代方案,例如在存储过程中实现我自己的评分,并再次迭代完整列表以至少确定完全匹配以将其排名更高?

如果这些都不起作用,我将不得不在我的应用程序层中完全构建评分。显然这会花费额外的资源,所以我想避免这种情况。

【问题讨论】:

    标签: mysql full-text-search innodb


    【解决方案1】:

    https://dev.mysql.com/doc/refman/5.6/en/fulltext-boolean.html

    分数是单词出现的时间量,因此对于所有单词,它都会出现一次,然后将结果分开。

    【讨论】:

      【解决方案2】:
      MATCH(name) AGAINST('battle*' IN BOOLEAN MODE)
          + 0.0001 * (name = 'battle')  AS score
      

      这应该匹配您示例中的所有单词,然后稍微提高完全匹配。

      当单词出现在文本字段的中间时进行提升:

         + 0.0001 * (REGEXP '[[:<:]]battle[[:>:]]')
      

      0.0001没有什么特别之处,它大到可以改变分数,但没有大到改变“结果”。)

      【讨论】:

        猜你喜欢
        • 2018-01-12
        • 2023-01-02
        • 1970-01-01
        • 2021-09-12
        • 2014-01-27
        • 1970-01-01
        • 1970-01-01
        • 2023-04-03
        • 2017-08-07
        相关资源
        最近更新 更多