Что нового в PostgreSQL 11: встроенный веб-поиск



    Продолжая тему интересных возможностей грядущего релиза PostgreSQL 11, я хотел бы рассказать про новую встроенную функцию websearch_to_tsquery. Соответствующий патч разработали Виктор Дробный и Дмитрий Иванов, с правками от Федора Сигаева. Давайте же разберемся, что реализовано в этом патче.

    Казалось бы, полнотекстовый поиск есть в PostgreSQL уже давно, и он очень даже неплохо работает. Что тут еще можно было добавить?

    Представьте, что вы делаете интернет-магазин на базе PostgreSQL и вам нужен поиск по товарам. Вот вам прилетела форма с поисковым запросом. Для поиска по базе из этого запроса нужно как-то построить tsvector. Можно сделать это с помощью функции to_tsquery. Но to_tsquery ожидает, что строка будет в определенном формате:

    =# select to_tsquery('foo bar baz');
    ERROR: syntax error in tsquery: "foo bar baz"

    =# select to_tsquery('foo & bar & baz');
    to_tsquery
    -----------------------
    'foo' & 'bar' & 'baz'

    Другими словами, в этом случае придется написать функцию, преобразующую запрос пользователя в запрос, понятный to_tsquery. Неудобно. Отчасти эту проблему решают функции plainto_tsquery и phraseto_tsquery:

    =# select plainto_tsquery('foo bar baz');
    plainto_tsquery
    -----------------------
    'foo' & 'bar' & 'baz'

    =# select phraseto_tsquery('foo bar baz');
    phraseto_tsquery
    ---------------------------
    'foo' <-> 'bar' <-> 'baz'

    Но с ними есть проблема. Дело в том, что пользователь может интуитивно воспользоваться кавычками или, скажем, какими-то булевыми операторами, потому что это работает у Google, Яндекса и других поисковых систем. Давайте посмотрим, что произойдет в этом случае:

    =# select plainto_tsquery('"foo bar" -baz or qux');
    plainto_tsquery
    -------------------------------
    'foo' & 'bar' & 'baz' & 'qux'

    Все сломалось! Ой. Неужели все-таки придется писать свой парсер?

    Вот чтобы его не приходилось писать с нуля для каждого приложения, начиная с PostgreSQL 11 соответствующий парсер теперь будет прямо в СУБД:

    =# select websearch_to_tsquery('"foo bar" -baz or qux');
    websearch_to_tsquery
    ----------------------------------
    'foo' <-> 'bar' & !'baz' | 'qux'

    Помимо того, что websearch_to_tsquery понимает кавычки, знак минус и булевы операторы, он интересен тем, что игнорирует любые попытки сделать синтаксическую ошибку. То есть, вы никогда не получите ошибку, на выходе всегда будет какой-то tsquery:

    =# select websearch_to_tsquery('-"foo bar" ((( baz or or qux !@#$%^&*_+-=');
    websearch_to_tsquery
    --------------------------------------
    !( 'foo' <-> 'bar' ) & 'baz' | 'qux'

    Еще из особенностей функции следует отметить тот факт, что она игнорирует любые скобки. То есть, вот так не прокатит:

    =# select websearch_to_tsquery('foo and (bar or baz)');
    websearch_to_tsquery
    -----------------------
    'foo' & 'bar' | 'baz'

    Данное поведение было выбрано из соображений, что нормальные люди (не айтишники :trollface:) на практике скобочки все равно не используют. Просто игнорируя их, мы существенно упрощаем реализацию фичи «сделать так, чтобы функция никогда не завершалась с ошибкой», да и разбор запроса будет работать быстрее. Возможно, флаг, включающий поддержку скобочек, появится в будущих версиях.

    Такая вот несложная, но полезная функция. Как минимум, она делает полнотекстовый поиск в PostgreSQL не хуже, чем он был до этого, и позволяет разработчикам упростить код своих приложений.
    Postgres Professional 219,66
    Российский вендор PostgreSQL
    Поделиться публикацией
    Похожие публикации
    Комментарии 11
    • +1
      Здорово!
      • 0

        Здорово, конечно, но со скобочками они погорячились! Не так сложно было и сделать их.


        На моей памяти никто из обычных пользователей просто так кавычки не вставляет.

        • +1

          В результате копипасты из соседней страницы могут появиться и кавычки, и скобки


          Например в одном магазине нашёл нужный ноут, пошел искать в другом: 15.6 LED " / 3840x2160 (Матрица TFT IPS) / Intel Core i7 7820HQ

        • +2

          Круто, реально хорошо, уже сталкивался с предыдущими методами))


          Но название нового метода не самое удачное, имхо
          Десктоп разработчики просто из-за названия могут пропустить этот метод, а у них тоже бывают поля для поиска)


          auto_to_tsquery, чуть более подходит и в будущем само название нормально позволяет добавлять возможностей))

          • +1
            Но название нового метода не самое удачное

            +1
            Может search_term_to_tsquery
            • 0

              Или даже что-то вроде any_to_tsquery

          • +1
            Спасибо, ждал такую фичу!
            • 0

              Сделали бы shared_ispell включенным по умолчанию лучше. Вообще не понимаю зачем делать было, чтобы каждое соединение больше 500мс тратилось на считывание словарей.

              • –2

                Спасибо за Вашу работу но хотелось бы чтобы


                1. была минимальная альтернатива MARIADB — Медиавики нормально с PostgreSQL не работает, форумные движки и CMS в основной массе тоже тоже, https://www.mediawiki.org/wiki/Manual:PostgreSQL Самоя простая корпоративная сеть начинается с корпоративной базы знаний на mediawiki — нельзя поставить PostgreSQL — ставим мариюДБ, раз уже использовали мариюДБ — значит и всё остальное будет на ней.
                2. Хотелось бы видеть на Вашем сайте Wiki на PostgreSQL + демоверсии основных CMS + бенчмарки. + сделайте примеры в стиле Установка Mediawiki (CMS) на LAPgP, LNgnixPgP, на ALTLinux (Для школоты и преподов информатики), AstraLinux для админов с зарплатой 20-25 т.р. госконтор. Затрат по времени для ваших инженеров будет 1-2 человеко дня, а количество установок и соответственно поток баг-отчётов возрастёт в разы.

                PS я как вы поняли несколько раз повёлся на ваши статьи и пытался использовать PostgreSQL но не получилось :( Энтузиазм ещё не угас.
                Окончательно… :).
                Удачи. Порвите ср-й MySQL с бекдорами АНБ!
                Снами Сноуден! MySQL будет разбит! Победа будет за PostgreSQL !

                • 0
                  А почему эту функцию не выпустить раньше релиза?
                  • 0
                    Релизный цикл не так работает и не для этого придуман. Желающие могут собрать PostgreSQL с этим патчем самостоятельно.

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

                  Самое читаемое