从输入/选择的文本中查找类似内容

时间:2012-03-08 14:59:35

标签: php mysql

我有一个用户在他们的购物篮中有一个项目,例如:Gears Of War 2限量版 - 我希望能够显示其他项目但不相似,更像是不同的版本,例如:战争的2个年度版本的游戏

所以我基本上想要做的事情,如果不可能的话,如果没有出现的话,用一个较少的单词进行搜索,然后再做一次,直到我得到所需的结果数,或最终没有单词。

所以,如果一个用户只是简单的“战争的齿轮”那么这很容易,因为有很多比赛,例如战争2的战争,战争的齿轮3等,当它是一个很大的独特标题时。

可行吗?这是最好的方法吗?

2 个答案:

答案 0 :(得分:1)

这样做的方法是首先选择名称与当前产品使用相同字词的产品,然后按照匹配的字数对其进行排序

我做了一个测试并使用了这个结构/内容的表:http://i.imgur.com/bwnNd.png

假设当前产品是id为1且标题为“Lorem ipsum dolor sit amet”的产品我将标题拆分为单词,选择标题中至少有一个单词的产品,订购列表按匹配的单词数量,只得到前几个(示例中为4)

在此之后,为了确保您获得更好的结果,不仅仅是匹配最大字数的那些,您可以使用字符串比较算法,如levenshtein距离。我使用了这个算法,因为php核心http://php.net/manual/en/function.levenshtein.php

中有一个函数

这个函数基本上告诉你需要在字符串上应用到另一个的转换数量(通过转换可以理解:删除一个字符,添加一个或更改一个字符的值)

因此,通过获得初始标题与每个结果的标题之间的levenshtein距离,您将知道更接近的标题

执行此操作时,您可以找到最小值(最好的,因为它告诉您需要最小的转换次数)并显示您找到此距离的产品

我在这里添加了一个示例脚本:http://codepad.org/FKDgo7ph

作为免责声明:您需要注意此脚本的安全性,这只是一个示例,并且还将其集成到您的系统中(此处产品的product_id和product_name是静态变量)

另外:通过添加一些改进可以获得更好的结果:

  • 实现从初始标题中删除的停用词列表(确保您没有获得“和”,“或”等词语的“积分”等。
  • 在获得分数之前反转单词并为匹配的每个单词分配不断增长的表现,这样可以确保标题开头的单词比最后的单词更重要

答案 1 :(得分:0)

如果你想只用一次MySQL调用就可以做到这一点。然后用一个简单的循环创建一个存储过程。

在每次迭代中将其抛入一个循环和一个单词

var_similar_title = 'Gears of War 2 Limited Edition'
....

SELECT
   product_name
FROM
   product
WHERE
   product_name LIKE CONCAT(var_similar_title,'%')

....

单词的简单方法是使用REVERSE(),LOCATE()和SUBSTRING()函数的组合。

类似的东西:

SET numWords = (length('gears of war')-length(REPLACE('gears of war', ' ', '')))/length(' ')

获取字符串中的单词计数(或者如果您愿意,可以从php程序中传递),然后使用

 SUBSTRING_INDEX('gears_of_war', i)

其中i最初为numWords,然后每次递减1次。

编辑:如果您需要更详细的示例,我会添加它:

DELIMITER $$
DROP PROCEDURE IF EXISTS findSimilarTitles$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `findSimilarTitles`( title VARCHAR(255), minMatches INT)
BEGIN

DECLARE i INT;
DECLARE var_similar_title VARCHAR(255);
DECLARE var_number_of_matches INT;
SET i = 1;
SET i = (length(title)-length(REPLACE(title, ' ', '')))/length(' ');

WHILE i > 0 DO
   SET title = SUBSTRING_INDEX(title, ' ', i);
   SET var_number_of_matches = (SELECT COUNT(*) FROM products WHERE product_name LIKE CONCAT(title,'%'));
   IF var_number_of_matches >= minMatches THEN
      SET i = -99;
   ELSE
     SET i = i - 1;
   END IF;
END WHILE;

IF i = -99 THEN
  SELECT product_name FROM products WHERE product_name LIKE CONCAT(title,'%');
ELSE
  SELECT 'No Matching Products';
END IF;

END$$