Пересечение множеств

  • Автор темы Болд
  • Дата начала

Болд

Guest
Пересечение множеств

Здравствуйте!
Есть следующая структура по поиску информации на сайте: все страницы парсятся - убираются комментарии, тэги и прочее. Потом каждая страница разбивается на слова.
В БД есть две таблицы: одна со словами и их id, вторая с id слов и id страниц, на которых они встретились.
таблицы:
create table words (word_id integer primary key, word varchar 255);
create table indexes (word_id integer, page_id integer);

Пример заполнения,
words
---------------------
word | word_id
---------------------
привет | 1
пока | 2
понедельник | 3
суббота | 4

indexes
-----------------
word_id | page_id
-----------------
1 | 1
1 | 2
2 | 2
2 | 3
3 | 1
3 | 3
3 | 4
4 | 2
4 | 4

Вопрос: как выбрать все страницы, на которых встретились нужные слова? Для одного слова все решается просто:
[sql]
SELECT DISTINCT indexes.page_id FROM indexes, words WHERE words.word_id LIKE 'слово%' AND words.word_id=indexes.word_id;
[/sql]


А для нескольких слов? Оператор OR возращает объединение - т.е. все страницы, на которых встретилось ХОТЬ ОДНО слово, а надо, чтобы только ВСЕ слова.
Решение через IN ('слово1', 'слово2') лишает прелести like 'слово%' - так решаются проблемы с окончаниями и прочие радости.

Сейчас работает через INTERSECT. Например,
[sql]
SELECT DISTINCT indexes.page_id FROM indexes, words WHERE words.word_id LIKE 'слово%' AND words.word_id=indexes.word_id INTERSECT SELECT DISTINCT indexes.page_id FROM indexes, words WHERE words.word_id LIKE 'слово2%' AND words.word_id=indexes.word_id;
[/sql]

Проблема: скорость выполнения (плюс intersect не работает в mysql). При 5, 6 и т.д. слов в запросе, время выполнения быстро растет. Нужны доли секунд, а при 5 словах уже приближается к секунде. Подскажите приемлимое решение, пожалуйста!
 

SelenIT

IT-лунатик :)
Вот такой вариант получился для 3-х слов:
[sql]
SELECT `indexes`.page_id
FROM `words`
LEFT JOIN `indexes` ON `words`.word_id = `indexes`.word_id
WHERE `words`.word LIKE 'привет'
OR `words`.word LIKE 'пока'
OR `words`.word LIKE 'понедельник'
GROUP BY `indexes`.page_id
HAVING count( DISTINCT `indexes`.word_id ) =3
[/sql]

Возможно, знатоки подскажут чего получше. И еще, по-моему, индексов явно не хватает, особенно второй таблице).

Правда, проблемы с окончаниями это тоже не решает. Но вообще-то решать эту проблему надо бы при заполнении индексной таблицы, а не при выборке из нее.
 

Болд

Guest
Спасибо, SelenIT

Автор оригинала: SelenIT
И еще, по-моему, индексов явно не хватает, особенно второй таблице).
Могу выложить и побольше пример ;-)

Автор оригинала: SelenIT
Правда, проблемы с окончаниями это тоже не решает. Но вообще-то решать эту проблему надо бы при заполнении индексной таблицы, а не при выборке из нее.
Жду предложений. Я не знаю, как это сделать до заполнения.
 

SelenIT

IT-лунатик :)
По поводу нехватки индексов я имел в виду, что таблице indexes нужен индекс по полю word_id. А таблице words, по идее, не помешал бы индекс по самому полю word.

По поводу выделения основы слова при составлении индекса - в Избранном на этом форуме есть неплохая подборка со ссылками на способы учета русской морфологии, словарь Зализняка и т.п.
 
Сверху