【问题标题】:Best way to improve (fuzzy) search results for similarities?改善(模糊)相似性搜索结果的最佳方法?
【发布时间】:2020-09-04 17:07:55
【问题描述】:

这个问题可能是一个重复的问题,但我将其退回,因为我无法完善解决方案。

对此感到抱歉。 现在我正在研究药物搜索引擎。用户不能总是输入准确的药物名称。根据用户输入的字符,我需要为他们获得更好的结果。但现在不是。我该怎么做才能更准确地做结果?例如,DB 中有信息:Анальгин, Цитрамон-П, Лирика-75мг 等...(在 西里尔文 中)。如果用户输入拉丁字母,系统会将其转换为西里尔字母并进行搜索。所以,我需要这样:即使用户在Цитрамон, cитрамон, ииттрамон or cтрамон 中输入单词,结果也应该返回Цитрамон。或者如果用户输入:Лирика, ЛЛЛирика, иииррика, Лика or Лирик,结果应该返回Лирика。或者Аналгин, Анагин ... 应该返回 Анальгин。 我应该得到类似的结果。我尝试了几种搜索算法和包(Laravel-Searchy、Laravel Scout、TNTSearch 等)但无济于事。现在搜索正在工作,但返回的结果与 SQL LIKE 运算符中的结果相同。另外,我尝试使用 Levenstein 距离如下: 我的搜索变量:

 $data = [];
 //dd($request->all());
 $search = _ltc($request->qry); // convert input text between latin and crylic 
  $data = Drug::selectRaw('*, levenshtein(?, `name`) as `diff`', [$search])
                ->havingBetween('diff', [0,4])
                ->limit(10)
                ->get();      

还有我的 SQL levenshtein 函数:

CREATE DEFINER = 'root'@'localhost'
  FUNCTION arzondori.levenshtein(s1 VARCHAR(255), s2 VARCHAR(255) )
  RETURNS INT(11)
 DETERMINISTIC
BEGIN 
DECLARE s1_len, s2_len, i, j, c, c_temp, cost INT; 
DECLARE s1_char CHAR; 
-- max strlen=255 
DECLARE cv0, cv1 VARBINARY(256); 
SET s1_len = CHAR_LENGTH(s1), s2_len = CHAR_LENGTH(s2), cv1 = 0x00, j = 1, i = 1, c = 0; 
IF s1 = s2 THEN 
 RETURN 0; 
 ELSEIF s1_len = 0 THEN 
 RETURN s2_len; 
 ELSEIF s2_len = 0 THEN 
 RETURN s1_len; 
ELSE 
WHILE j <= s2_len DO 
 SET cv1 = CONCAT(cv1, UNHEX(HEX(j))), j = j + 1; 
END WHILE; 
WHILE i <= s1_len DO 
 SET s1_char = SUBSTRING(s1, i, 1), c = i, cv0 = UNHEX(HEX(i)), j = 1; 
WHILE j <= s2_len DO 
  SET c = c + 1; 
  IF s1_char = SUBSTRING(s2, j, 1) THEN  
    SET cost = 0; ELSE SET cost = 1; 
  END IF; 
  SET c_temp = CONV(HEX(SUBSTRING(cv1, j, 1)), 16, 10) + cost; 
  IF c > c_temp THEN SET c = c_temp; END IF; 
    SET c_temp = CONV(HEX(SUBSTRING(cv1, j+1, 1)), 16, 10) + 1; 
    IF c > c_temp THEN  
      SET c = c_temp;  
    END IF; 
   SET cv0 = CONCAT(cv0, UNHEX(HEX(c))), j = j + 1; 
  END WHILE; 
      SET cv1 = cv0, i = i + 1; 
     END WHILE; 
    END IF; 
   RETURN c; 
  END

我还考虑了以下选项。

$data = Drug::select("id", "name")
                ->where('name', 'LIKE', "%$search%")
                ->get();
 $data5 = Searchy::search('drugs')
                   ->fields('name')
                   ->query($search)
                   ->select('id', 'name')
                   ->get();

谁能帮助找到解决这个问题的方法?如果问题有点令人困惑,请提前抱歉! 谢谢!

【问题讨论】:

    标签: php sql laravel levenshtein-distance fuzzy-search


    【解决方案1】:

    这将很难以您尝试的方式解决。您需要像 Sphinx 或弹性搜索这样的全文搜索引擎。它支持语言和模糊搜索。更多信息在这里:https://en.wikipedia.org/wiki/Full-text_search

    我推荐狮身人面像: http://sphinxsearch.com/docs/sphinx3.html#features-overview

    但是文档非常繁重。另一个选择是具有非常好的文档的 elasticsearch。

    尝试去发明这个你自己会很棘手,你需要时间才能得到好的结果。

    【讨论】:

    • 好的,谢谢兄弟!我会试试你说的方法。第一种方法有点令人满意。另外,你能为 Elasticsearch 推荐任何好的库吗?更接近我的问题?
    【解决方案2】:

    我知道您已经接受了另一个答案,像 Sphinx 或 Elasticsearch 这样的全文搜索工具是一个不错的选择,但对于您的用例来说,还有另一个可能更简单。

    您没有提及您使用的是什么数据库,但其中许多数据库至少支持全文搜索。例如,在 MariaDB 和 MySQL 中,您可以搜索 FUL​​LTEXT 索引。首先你需要创建索引:

    ALTER TABLE drugs ADD FULLTEXT (name);
    

    然后,您可以将查询中的 LIKE 子句替换为针对索引列的 MATCH 子句,如下例所示:

    Drug::whereRaw('MATCH(name) AGAINST (?)', [$search]);
    

    全文搜索有很多选项,所以如果你想扩展它以允许或多或少的结果中的歧义,或者根据匹配的质量对结果进行排序,这是可能的,但不知道你是什么数据库'重新使用我无法详细说明,所以我建议您查看数据库的文档。与全文索引匹配不仅允许比 LIKE 子句更多的歧义,而且还具有更高的性能。如果您的用例足够简单以至于您不需要单独的搜索后端(听起来就是这样),那么您的数据库的全文搜索能力可能就足够了,而且它可能比集成 Elasticsearch 更快、更容易。

    【讨论】:

    • 谢谢,我使用的是 MySQL 5.7。我尝试了全文搜索,但它是从一个字母到另一个字母的搜索。也就是说,如果我键入google,它会产生以g 开头的其他结果,但它在db google 字中可用。在不存在的字母上绘制结果。
    • MySQL 5.7 应该能够做你想做的事,但查询可能需要调整。 dev.mysql.com/doc/refman/5.7/en/fulltext-natural-language.html 的文档应该可以帮助您入门。您应该可以使用ORDER BY MATCH(name) DESC 之类的东西按分数排序,而 Eloquent 有一个 orderByRaw() 方法可以通过它。
    • 好的兄弟!我尝试了所有这些,也尝试了您的Drug::whereRaw('MATCH(name) AGAINST (?)', [$search]); 示例,但它没有返回任何内容。全文搜索,只搜索类似的词,比如如果我输入 google 它找到但如果我输入 goo 它不匹配任何内容。
    猜你喜欢
    • 1970-01-01
    • 2014-06-09
    • 2018-12-24
    • 2015-08-14
    • 2015-10-09
    • 1970-01-01
    • 2013-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多