Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/242.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 从输入/选择的文本中查找类似内容_Php_Mysql - Fatal编程技术网

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

Php 从输入/选择的文本中查找类似内容,php,mysql,Php,Mysql,我有一个用户在他们的购物篮中有一个项目,例如:Gears Of War 2限量版-我希望能够显示其他项目,但不类似,更像不同版本,例如Gears Of War 2年度游戏版 所以我基本上想做的是,如果可能的话,用少一个单词进行搜索,如果没有找到任何单词,然后再进行搜索,直到得到所需的结果数,或者最终没有单词 因此,如果一个用户只是简单的“战争装备”,那么这很容易,因为有很多匹配,例如战争装备2,战争装备3等,当它是一个大的独特的标题 这可行吗?这是最好的方法吗?如果您只需要一个MySQL调用就可

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

所以我基本上想做的是,如果可能的话,用少一个单词进行搜索,如果没有找到任何单词,然后再进行搜索,直到得到所需的结果数,或者最终没有单词

因此,如果一个用户只是简单的“战争装备”,那么这很容易,因为有很多匹配,例如战争装备2,战争装备3等,当它是一个大的独特的标题


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

如果您只需要一个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$$

实现这一点的一种方法是,首先选择名称与当前产品使用相同单词的产品,然后根据匹配的单词数对其进行排序

我做了一个测试,并使用了一个使用此结构/内容的表格:

假设当前产品是id为1且标题为“Lorem ipsum dolor sit amet”的产品,我将标题拆分为多个单词,选择标题中至少有一个单词的产品,按照匹配的单词数对列表进行排序,并仅获得前几个单词(示例中为4个)

在此之后,为了确保获得更好的结果,而不仅仅是与最大字数匹配的结果,您可以使用类似levenshtein距离的字符串比较算法。我使用了这个算法,因为php核心中有一个函数用于此

基本上,此函数告诉您需要对字符串进行多少次转换才能到达另一个字符串(通过转换可以理解为:删除一个字符、添加一个字符或更改一个字符的值)

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

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

我在这里添加了一个示例脚本:

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

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

  • 执行一个从初始标题中删除的停止词列表(确保“和”、“或”等词不会得到“分”)
  • 在获得分数之前,倒转单词,并为每个匹配的单词指定一个增长的表现,这样可以确保标题开头的单词比结尾的单词更重要

你是否有可能保留一张“系列”表格,并让该系列中的任何游戏通过“系列id”字段与之关联?@Dave不,不幸的是,数据每天都在变化,因为它来自不同的来源,但它并不总是战争的齿轮,它可能是“fifa 2011鲁尼头发版”或者类似的东西很明显,您会将项的名称作为参数传递。LOL。我只是演示如何做,您需要在存储过程中用变量替换这些字符串。@DarrenSweeney我添加了一个您应该能够使用的更详细的示例。要执行存储过程这
呼叫findSimilarTitles(,)
谢谢,这对我的学习非常有帮助,非常感谢。