Сопоставление специальных символов (например, #, +) с помощью 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, если это возможно.


person Lev    schedule 15.10.2013    source источник


Ответы (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. Я смотрю на это дальше.

person garbo999    schedule 06.10.2015