запрос, который выполняет логику AND для ключевых слов и возвращает каждый такой класс, для которого в классе или его имени присутствуют поисковые термины - PullRequest
0 голосов
/ 14 июня 2010

Сначала выведите эти данные

CREATE TABLE IF NOT EXISTS `all_tag_relations` (
  `id_tag_rel` int(10) NOT NULL AUTO_INCREMENT,
  `id_tag` int(10) unsigned NOT NULL DEFAULT '0',
  `id_tutor` int(10) DEFAULT NULL,
  `id_wc` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`id_tag_rel`),
  KEY `All_Tag_Relations_FKIndex1` (`id_tag`),
  KEY `id_wc` (`id_wc`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=19 ;


INSERT INTO `all_tag_relations` (`id_tag_rel`, `id_tag`, `id_tutor`, `id_wc`) VALUES
(1, 1, 1, NULL),
(2, 2, 1, NULL),
(3, 6, 2, NULL),
(4, 7, 2, NULL),
(8, 3, 1, 1),
(9, 4, 1, 1),
(10, 5, 2, 2),
(11, 4, 2, 2),
(15, 8, 1, 3),
(16, 9, 1, 3),
(17, 10, 1, 4),
(18, 4, 1, 4),
(19, 1, 2, 5),
(20, 4, 2, 5);

CREATE TABLE IF NOT EXISTS `tags` (
  `id_tag` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `tag` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id_tag`),
  UNIQUE KEY `tag` (`tag`),
  KEY `id_tag` (`id_tag`),
  KEY `tag_2` (`tag`),
  KEY `tag_3` (`tag`),
  KEY `tag_4` (`tag`),
  FULLTEXT KEY `tag_5` (`tag`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;



INSERT INTO `tags` (`id_tag`, `tag`) VALUES
(1, 'Sandeepan'),
(2, 'Nath'),
(3, 'first'),
(4, 'class'),
(5, 'new'),
(6, 'Bob'),
(7, 'Cratchit'),
(8, 'more'),
(9, 'fresh'),
(10, 'second');

CREATE TABLE IF NOT EXISTS `webclasses` (
  `id_wc` int(10) NOT NULL AUTO_INCREMENT,
  `id_author` int(10) NOT NULL,
  `name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id_wc`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;



INSERT INTO `webclasses` (`id_wc`, `id_author`, `name`) VALUES
(1, 1, 'first class'),
(2, 2, 'new class'),
(3, 1, 'more fresh'),
(4, 1, 'second class'),
(5, 2, 'sandeepan class');

О системе - Система состоит из репетиторов и классов. - Данные в таблице All_Tag_Relations хранят отношения тегов для каждого зарегистрированного репетитора и каждого класса, созданного репетитором. Отношения тегов используются для поиска классов.

Текущий дамп данных соответствует репетитору "Sandeepan Nath", который создал классы с именами "первый класс", "более свежие", "второй класс", и репетитору "Bob Cratchit", который создал классы "новый класс" и "Sandeepan" класс».

Я пытаюсь получить поисковый запрос, который выполняет логику AND для поисковых ключевых слов и возвращает каждый такой класс, для которого поисковые термины присутствуют в имени класса или его наставнике.

Для упрощения приведем пример списка поисковых терминов и желаемых результатов:


Search term         result classes (check the id_wc in the results)**

first class              1

Sandeepan Nath class     1

Sandeepan Nath           1,3

Bob Cratchit             2

Sandeepan Nath bob       none

Sandeepan Class          1,4,5

Я дошел до этого запроса

-- Two keywords search


SET @tag1 = 4, @tag2 = 1; -- Setting some user variables to see where the ids go.

SELECT wc.id_wc, sum( DISTINCT (
wtagrels.id_tag = @tag1
) ) AS key_1_class_matches, 
sum( DISTINCT (
wtagrels.id_tag = @tag2
) ) AS key_2_class_matches,
sum( DISTINCT (
ttagrels.id_tag = @tag1
) ) AS key_1_tutor_matches,
sum( DISTINCT (
ttagrels.id_tag = @tag2
) ) AS key_2_tutor_matches,
sum( DISTINCT (
ttagrels.id_tag = wtagrels.id_tag
) ) AS key_class_tutor_matches

FROM WebClasses as wc 
join all_tag_relations AS wtagrels on wc.id_wc = wtagrels.id_wc
join all_tag_relations as ttagrels on (wc.id_author = ttagrels.id_tutor)

WHERE (
wtagrels.id_tag = @tag1
OR wtagrels.id_tag = @tag2
OR ttagrels.id_tag = @tag1
OR ttagrels.id_tag = @tag2
)
GROUP BY wtagrels.id_wc
LIMIT 0 , 20

Для поиска с 1 или 3 терминами удалите / добавьте переменную часть в этом запросе. Табулирование моих наблюдений за значениями key_1_class_matches, key_2_class_matches, key_1_tutor_matches (скажем, ключи классов), key_2_tutor_matches для различных случаев (скажем, ключей репетитора).


Search term           expected result                 Observation
first class              1              for class 1, all class keys+all tutor keys =1

Sandeepan Nath class     1              for class 1, one class key+ all tutor keys = 1

Sandeepan Nath           1,3            both tutor keys =1 for these classes

Bob Cratchit             2              both tutor keys = 1

Sandeepan Nath bob       none           no complete tutor matches for any class

Я обнаружил шаблон, в котором в любом случае класс (ы), которые должны появляться в результате, имеют наибольшее количество совпадений (все ключи классов и ключи преподавателя). Например. поиск "первый класс", только для класса = 1, всего совпадений ключей = 4 (1 + 1 + 1 + 1) при поиске "Sandeepan Nath" для классов 1, 3,4 (все классы от Sandeepan Nath) совпадают все ключи преподавателя.

Но в поиске "Sandeepan Class" нет шаблона - классы 1,4,5 должны совпадать. Теперь, как мне вставить условие в запрос на основе этого шаблона, чтобы возвращались только эти классы.

Нужно ли мне использовать полнотекстовый поиск здесь, потому что он дает оценку / ранг, указывающий силу соответствия? Любой пример запроса поможет.

Обратите внимание - Я уже нашел решение для отображения классов, когда какие-либо / все условия поиска совпадают с именем класса. Mysql - Помогите мне изменить этот поисковый запрос, чтобы получить желаемые результаты Но если все поисковые термины указаны в имени преподавателя, это не сработает. Итак, я модифицирую запрос и экспериментирую.

Ответы [ 2 ]

1 голос
/ 17 июня 2010

Я думаю, что ваш дизайн не так хорош, и его трудно понять, потому что вы смешиваете учителей и теги в одной таблице.Вот почему еще сложнее сделать запрос, чтобы получить желаемые результаты.В ваших примерах с Search term и result classes трудно сказать, когда вы хотите искать по тегу (= слово в имени класса) или по тегу (= имя преподавателя)

Я предлагаю использоватьследующие таблицы:
(Если в tags есть только слова с именем webclasses, вы можете искать в этой таблице с помощью LIKE и удалять таблицы tags и all_tag_relations.)

CREATE TABLE `tutors` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(64) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `tutors` (`id`,`name`) VALUES (1,'Sandeepan Nath'), (2,'Bob Cratchit');

CREATE TABLE `webclasses` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id_tutor` int(10) unsigned NOT NULL,
  `name` varchar(64) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `webclasses` (`id`, `id_tutor`, `name`) VALUES
(1, 1, 'first class'),(2, 2, 'new class'),(3, 1, 'more fresh'), (4, 1, 'second class'),(5, 2, 'sandeepan class');

CREATE TABLE `tags` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `tag` varchar(64) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `tags` (`id`, `tag`) VALUES
(1, 'sandeepan'),(3, 'first'),(4, 'class'),(5, 'new'),(8, 'more'),(9, 'fresh'),(10, 'second');

CREATE TABLE `all_tag_relations` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id_tag` int(10) unsigned NOT NULL,
  `id_wc` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='Tags of classes';
INSERT INTO `all_tag_relations` (`id_tag`, `id_wc`) VALUES
(3, 1),(4, 1),(5, 2),(4, 2),(8, 3),(9, 3),(10,4),(4, 4),(1, 5),(4, 5);

Поиск по тегам:

SELECT wc.*, COUNT(*) as tag_count, rel.id_tag from webclasses wc
LEFT JOIN all_tag_relations rel ON wc.id = rel.id_wc
WHERE (rel.id_tag = 3 OR rel.id_tag=4)
GROUP BY wc.id
HAVING tag_count!=1;

Я ставлю tag_count!=1, потому что, если вы добавите условия для репетиторов, tag_count будет 0, когда все теги не в классеназвание.В противном случае tag_count всегда больше, чем 0.

. Я бы предложил использовать REGEXP для частичного соответствия, например, если пользователь вводит firs clas, запрос будет

SELECT * FROM webclasses 
WHERE 1 
      AND name REGEXP '([[:<:]]firs.*)'
      AND name REGEXP '([[:<:]]clas.*)'
*.1027 * (я поставил WHERE 1, потому что в вашем приложении вы можете поместить условия в цикл foreach с помощью AND name ... после разделения текста на пробелы.)

В результате получается класс 1 - first class

Чтобы выбрать данные из таблицы преподавателей, вы можете создать представление из следующего запроса:

SELECT wc.*, tut.name AS `tutor_name` FROM webclasses wc
LEFT JOIN tutors tut ON wc.id_tutor = tut.id;

и добавить некоторые дополнительные условия в предыдущем запросе.


PS Почему вы говорите, что для Bob Cratchit результирующие классы должны быть только 2, а не 2, 5?потому что 5 его класс тоже.

0 голосов
/ 20 июня 2010

Я нашел решение сам. Я так счастлив !!!

Ключ лежит в отдельных таблицах отношений тегов для преподавателей и классов. то есть две таблицы под названием tutors_tag_relations и webclasses_tag_relations вместо all_tag_relations, как указано ниже:

CREATE TABLE IF NOT EXISTS `tutors_tag_relations` (
  `id_tag_rel` int(10) NOT NULL AUTO_INCREMENT,
  `id_tag` int(10) unsigned NOT NULL DEFAULT '0',
  `id_tutor` int(10) DEFAULT NULL,
  PRIMARY KEY (`id_tag_rel`),
  KEY `All_Tag_Relations_FKIndex1` (`id_tag`),
  KEY `id_tag` (`id_tag`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;


INSERT INTO `tutors_tag_relations` (`id_tag_rel`, `id_tag`, `id_tutor`) VALUES
(1, 1, 1),
(2, 2, 1),
(3, 6, 2),
(4, 7, 2);


CREATE TABLE IF NOT EXISTS `webclasses_tag_relations` (
  `id_tag_rel` int(10) NOT NULL AUTO_INCREMENT,
  `id_tag` int(10) unsigned NOT NULL DEFAULT '0',
  `id_tutor` int(10) DEFAULT NULL,
  `id_wc` int(10) DEFAULT NULL,
  PRIMARY KEY (`id_tag_rel`),
  KEY `webclasses_Tag_Relations_FKIndex1` (`id_tag`),
  KEY `id_wc` (`id_wc`),
  KEY `id_tag` (`id_tag`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=21 ;

INSERT INTO `webclasses_tag_relations` (`id_tag_rel`, `id_tag`, `id_tutor`, `id_wc`) VALUES
(1, 3, 1, 1),
(2, 4, 1, 1),
(3, 5, 2, 2),
(4, 4, 2, 2),
(15, 8, 1, 3),
(16, 9, 1, 3),
(17, 10, 1, 4),
(18, 4, 1, 4),
(19, 1, 2, 5),
(20, 4, 2, 5);

Тогда этот запрос работает: -

SET @tag1 = 4, @tag2 = 1; -- Setting some user variables to see where the ids go.

SELECT wc.id_wc, sum( DISTINCT (
wtagrels.id_tag = @tag1 or ttagrels.id_tag = @tag1
) ) AS key_1_matches,
sum( DISTINCT (
wtagrels.id_tag = @tag2 or ttagrels.id_tag = @tag2
) ) AS key_2_matches

FROM WebClasses as wc
join webclasses_tag_relations AS wtagrels on wc.id_wc = wtagrels.id_wc
join tutors_tag_relations as ttagrels on (wc.id_author = ttagrels.id_tutor)

WHERE (
wtagrels.id_tag = @tag1
OR wtagrels.id_tag = @tag2
OR ttagrels.id_tag = @tag1
OR ttagrels.id_tag = @tag2
)
GROUP BY wtagrels.id_wc
having key_1_matches = 1 and key_2_matches=1
LIMIT 0 , 20
...