Использование левенштейна на частях струны в SQL - PullRequest
1 голос
/ 07 августа 2020

Я пытаюсь найти способ задействовать некоторые нечеткие методы поиска в поле поиска в нашем магазине, используя метод Левенштейна, но у меня возникла проблема с поиском только части названий продуктов.

Например, клиент ищет scisors, но у нас есть продукт под названием electric scissor. Используя метод Левенштейна levenshtein("scisors","electric scissor"), мы получим результат 11, потому что электрическая c часть будет считаться разницей.

Я ищу способ просмотра подстрок название продукта, чтобы он сравнил его с levenshtein("scisors","electric"), а затем также с levenshtein("scisors","scissor"), чтобы увидеть, что мы можем получить результат только 2 во второй подстроке и, таким образом, показать этот продукт как часть их результата поиска.

Нерабочий пример, чтобы дать вам представление о том, что мне нужно:

SELECT * FROM products p WHERE levenshtein("scisors", p.name) < 5

Вопрос: Есть ли способ написать оператор SQL, который обрабатывает проверку для частей строки? Нужно ли мне создавать дополнительные функции в моей базе данных, чтобы иметь возможность обрабатывать их, возможно, или изменять мою существующую функцию, и если да, то как бы это выглядело?

В настоящее время я использую эту реализацию метода levenshtein:

//levenshtein(s1 as VARCHAR(255), s2 as VARCHAR(255))
//returns int


  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

1 Ответ

0 голосов
/ 07 августа 2020

Это многовато для комментария.

Во-первых, я бы предложил использовать полнотекстовый поиск со списком синонимов. Тем не менее, у вас могут быть пользователи с очень плохими орфографическими способностями, поэтому список синонимов может быть трудно поддерживать.

Если вы используете расстояние Левенштейна, то я предлагаю делать это на на слово основание. Для каждого слова, введенного пользователем, вычислите ближайшее слово в поле name. Затем сложите их, чтобы получить наилучшее соответствие.

В вашем примере у вас будут следующие сравнения:

  • levenshtein ('scisors', 'electri c')
  • levenshtein ('ножницы', 'ножницы')

Минимум будет вторым. Если пользователь вводит несколько слов, например 'electrk scisors', вы должны набрать

  • levenshtein ('electrk', 'electri c') <- минимум </li>
  • levenshtein ('электрк', 'ножницы')
  • levenshtein ('ножницы', 'electri c')
  • levenshtein ('ножницы', 'ножницы') <- минимум </li>

Вероятно, это интуитивно понятный способ подойти к поиску.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...