Соответствие специальным символам (например, #, +) с использованием pg_search
Я использую гем pg_search в приложении Rails для поиска пользователей - их биографии и связанной с ними модели навыков. Пользователи являются разработчиками, поэтому их навыки включают такие вещи, как "CSS", "C++", "C#", "Objective C" и т. Д.
Первоначально я использовал следующую область поиска:
pg_search_scope :search,
against: [:bio],
using: {tsearch: {dictionary: "english", prefix: true}},
associated_against: {user: [:fname, :lname], skills: :name}
Однако, если вы будете искать "C++" в этом случае, вы получите результаты, которые включают "CSS" (среди прочего). Я изменил область, чтобы использовать "простой" словарь и удалил префикс:
pg_search_scope :search_without_prefix,
against: [:bio],
using: {tsearch: {dictionary: "simple"}},
associated_against: {user: [:fname, :lname], skills: :name}
Это исправило некоторые вещи - например, поиск "C++" не показывает "CSS". Но поиск "C++" или "C#" по-прежнему соответствует пользователям, у которых в списке есть "C" или "Objective C".
Я определенно могу сделать основной ILIKE
совпадать, но надеяться сделать это с помощью pg_search, если это возможно.
1 ответ
Я бы прокомментировал, но у меня пока недостаточно репутации.
я учился pg_search
что привело меня глубже в полнотекстовый поиск PostgreSQL. Это сложный модуль, но в нем есть команда ts_debug(), помогающая понять, как анализируются входные строки. Вывод ts_debug() для тестовой строки "C++ CSS C# Objective C" очень показателен. Похоже, что "# и"+"рассматриваются как пробелы в конфигурации по умолчанию для английского языка. Я думаю, что вам, возможно, придется изменить синтаксический анализатор в PostgreSQL, чтобы получить желаемое поведение.
postgres=# SELECT * FROM ts_debug('english', 'C++ CSS C# Objective C');
alias | description | token | dictionaries | dictionary | lexemes
-----------+-----------------+-----------+----------------+--------------+----------
asciiword | Word, all ASCII | C | {english_stem} | english_stem | {c}
blank | Space symbols | + | {} | |
blank | Space symbols | + | {} | |
asciiword | Word, all ASCII | CSS | {english_stem} | english_stem | {css}
blank | Space symbols | | {} | |
asciiword | Word, all ASCII | C | {english_stem} | english_stem | {c}
blank | Space symbols | # | {} | |
asciiword | Word, all ASCII | Objective | {english_stem} | english_stem | {object}
blank | Space symbols | | {} | |
asciiword | Word, all ASCII | C | {english_stem} | english_stem | {c}
(10 rows)
Кстати, вот очень полезный учебник, если вы хотите изучить PostgreSQL полнотекстовый поиск: http://shisaa.jp/postset/postgresql-full-text-search-part-1.html
ОБНОВИТЬ:
Я нашел решение в рамках полнотекстового поиска PostgreSQL. Это предполагает использование test_parser
расширение, которое описано здесь: http://www.postgresql.org/docs/9.1/static/test-parser.html
Сначала требуется некоторая конфигурация в psql
:
postgres=# CREATE EXTENSION test_parser;
postgres=# CREATE TEXT SEARCH CONFIGURATION testcfg ( PARSER = testparser );
postgres=# ALTER TEXT SEARCH CONFIGURATION testcfg
ADD MAPPING FOR word WITH english_stem;
Теперь вы можете проиндексировать тестовую строку и увидеть, что такие термины, как "C++", обрабатываются как отдельные токены по желанию:
postgres=# SELECT to_tsvector('testcfg', 'C++ CSS C# Objective C #GT40 GT40 added joined');
to_tsvector
----------------------------------------------------------------------------
'#gt40':6 'ad':8 'c':5 'c#':3 'c++':1 'css':2 'gt40':7 'join':9 'object':4
(1 row)
Остается вопрос о том, как интегрировать это в pg_search
, Я смотрю на это дальше.