Mysql релевантность полнотекстового поиска по нескольким таблицам - PullRequest
13 голосов
/ 26 января 2012

Мне было поручено создать функцию поиска по всему сайту.Для поиска нужно посмотреть статьи, события и содержимое страницы

Я уже использовал MATCH () / AGAINST () в MySQL и знаю, как получить релевантность результата, но насколько я знаю релевантностьуникальна для поиска (содержимое, количество строк и т. д.), релевантность результатов из таблицы статей не будет соответствовать релевантности результатов из таблицы событий.

Есть ли способ объединить релевантность, чтобы результаты были получены из всехтри таблицы имеют сопоставимую актуальность?

Ответы [ 2 ]

22 голосов
/ 31 марта 2012

Да, вы можете очень хорошо объединить их, используя такие поисковые системы, как Apache Lucene и Solr.

http://lucene.apache.org/solr/

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

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

Например, предположим, вы хотите, чтобы статьи были наиболее важными, события - средне важными, а страницы - наименее важными. Вы можете использовать множители, как это:

set @articles_multiplier=3;
set @events_multiplier=2;
set @pages_multiplier=1;

Вот рабочий пример, который вы можете попробовать, демонстрирующий некоторые из этих методов:

Создать пример данных:

create database d;
use d;

create table articles (id int primary key, content text) ENGINE = MYISAM;
create table events (id int primary key, content text) ENGINE = MYISAM;
create table pages (id int primary key, content text) ENGINE = MYISAM;

insert into articles values 
(1, "Lorem ipsum dolor sit amet"),
(2, "consectetur adipisicing elit"),
(3, "sed do eiusmod tempor incididunt");

insert into events values 
(1, "Ut enim ad minim veniam"),
(2, "quis nostrud exercitation ullamco"),
(3, "laboris nisi ut aliquip");

insert into pages values 
(1, "Duis aute irure dolor in reprehenderit"),
(2, "in voluptate velit esse cillum"),
(3, "dolore eu fugiat nulla pariatur.");

Сделать его доступным для поиска:

ALTER TABLE articles ADD FULLTEXT(content);
ALTER TABLE events ADD FULLTEXT(content);
ALTER TABLE pages ADD FULLTEXT(content);

Используйте UNION для поиска во всех этих таблицах:

set @target='dolor';

SELECT * from (
  SELECT 
    'articles' as 'table_name', id, 
    @articles_multiplier * (MATCH(content) AGAINST (@target)) as relevance
    from articles
  UNION
  SELECT 
    'events' as 'table_name', 
    id,
    @events_multiplier * (MATCH(content) AGAINST (@target)) as relevance
    from events
  UNION
  SELECT 
    'pages' as 'table_name', 
    id, 
    @pages_multiplier * (MATCH(content) AGAINST (@target)) as relevance
    from pages
)
as sitewide WHERE relevance > 0;

Результат:

+------------+----+------------------+
| table_name | id | relevance        |
+------------+----+------------------+
| articles   |  1 | 1.98799377679825 |
| pages      |  3 | 0.65545331108093 |
+------------+----+------------------+
2 голосов
/ 25 сентября 2014

(Извините, я хочу оставить это как комментарий к ответу выше, но у меня недостаточно репутации, чтобы комментировать)

Помните, что UNION в подзапросах очень плохо оптимизирован. Часто случается, когда вы хотите разбить на страницы свои результаты, используя «LIMIT @page * 10, 10» в родительском запросе, тогда MySQL должен получить все результаты из подзапросов, чтобы оценить родительский запрос.

...