Объедините простой текстовый поиск со сложным в Postgres - PullRequest
0 голосов
/ 31 декабря 2018

В настоящее время я пытаюсь выяснить, как мне следует обрабатывать функцию поиска в моем приложении.Чтобы показать, какая проблема у меня есть в настоящее время, я создал вымышленную таблицу базы данных.

+----+--------------+-----------+----------+---------------------------------------------------------------------------------+------------------------+
| id |   username   | firstname | lastname |                                   description                                   |         email          |
+====+==============+===========+==========+=================================================================================+========================+
|  1 | example.hans | Hans      | Example  | Some randome user called Hans. It doesn't really matter what the description is | example@test.com       |
|  2 | root         | Root      | Root     | Some other user                                                                 | root@localhost         |
|  3 | Shawn94      | Leo       | Larson   | Loves to play with firework                                                     | leo.larson@hotmail.com |
+----+--------------+-----------+----------+---------------------------------------------------------------------------------+------------------------+

Это, конечно, нет реальных данных.

Я знаю, что могу создать вид полнотекстового поискав postgres с to_tsvector и to_tsquery.Но проблема этого метода в том, что я не могу работать с небольшими значениями, такими как имя пользователя, имя или фамилия.Если бы я использовал термин запроса leo, postgres, вероятно, не нашел бы пользователя с идентификатором 3, поскольку поисковый термин и целевое значение слишком малы.Проблема, если бы я использовал fuzzymatching (пример: levenshtein), у меня была бы проблема с описанием.Левенштейн прекрасно работает на небольших ценностях.Тем не менее, это не очень хорошо работает с текстом.

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

Вот пример запроса, как я пытался его сбалансировать:

SELECT "id" as "id",
       (
           (ts_rank_cd(to_tsvector("user"."description"), to_tsquery('Bee')))
           -
           (
             (
               SELECT MIN("LEVENSHTEIN_VALUES")
               FROM unnest(
                        ARRAY [levenshtein("user"."fullName", 'Bee'), levenshtein("user"."username", 'Bee'), levenshtein("user"."email", 'Bee')]) AS "LEVENSHTEIN_VALUES"
             )
           )
         )                      AS "FULLTEXT_RANK"
FROM "user" "user"
ORDER BY "FULLTEXT_RANK" ASC
LIMIT 10;

Нет гарантии, что этот запрос действительно работает, потому что я взял его из своего приложения и изменил, чтобы он соответствовал примеруdata.

Объяснение того, что я пытался:

Сначала создайте значение ранга с помощью ts_rank_cd в поле описания (на самом деле в реальном приложении мне потребуется текстовый поиск по нескольким столбцам).Затем я получаю значения Левенштейна для каждого поля и использую наименьшее значение, чтобы вычесть его из ts_rank_cd.Вот как я пытался уравновесить Левенштейна с Цвектором.Но, конечно, этот метод имеет огромный недостаток.Если каждый столбец Левенштейна полностью отличается от поискового запроса, но в описании есть искомый термин, возможно, что искомая строка все еще получает низкий рейтинг FULLTEXT_RANK из-за индекса Левенштейна.

Какможно ли объединить полнотекстовый поиск с нечетким сопоставлением?

Редактировать:

SELECT *,
       (
         SELECT SUM("TS_AND_SIM_RANK")
         FROM unnest(ARRAY [
           (SELECT MAX("TS_RANK")
            FROM unnest(ARRAY [
              ts_rank(to_tsvector('simple', "user"."description"), phraseto_tsquery('simple', ?))
              ]) AS "TS_RANK"),
           (SELECT MAX("SIM_RANK")
            FROM unnest(ARRAY [
              similarity("user"."username", ?),
              similarity("user"."firstname", ?),
              similarity("user"."lastname", ?)
              ]) AS "SIM_RANK")
           ]) AS "TS_AND_SIM_RANK"
       ) as "RANK"
FROM "user"
ORDER BY "RANK" DESC;

Это еще одна идея, как я мог это сделать.Но есть еще некоторые проблемы.

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