выборка максимальных элементов массива

phprus

Moderator
Команда форума
Gas
Ты сортируешь статьи по количеству тагов у них, а это мало похоже на меру популярности.
Думаю, что здесь точно такая-же ситуация, как и с выборкой популярных статей по категориям (это был изначальный вопрос данной темы). По сути же категории от таков ничем не отличаются, да и структура связей таблиц похожа.
 

Lifeline

Новичок
Спасибо за участие. Думаю задача довольно стандартная, но почему то готового варианта нагуглить не удалось.

Сразу сорри за большую месагу, основное в ней дапм.


База

CREATE TABLE IF NOT EXISTS `art2tag` (
`article_id` int(10) unsigned NOT NULL,
`tag_id` int(10) unsigned NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;


INSERT INTO `art2tag` (`article_id`, `tag_id`) VALUES
(1, 1),
(1, 2),
(2, 1),
(2, 3),
(3, 1),
(3, 2),
(4, 3),
(4, 4);

CREATE TABLE IF NOT EXISTS `articles` (
`article_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`category_id` int(10) unsigned NOT NULL,
`views` int(10) unsigned NOT NULL,
PRIMARY KEY (`article_id`),
KEY `ctg_views` (`category_id`,`views`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;


INSERT INTO `articles` (`article_id`, `category_id`, `views`) VALUES
(1, 1, 100),
(2, 1, 100),
(3, 2, 50),
(4, 2, 100);

CREATE TABLE IF NOT EXISTS `tags` (
`tag_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL,
PRIMARY KEY (`tag_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;


INSERT INTO `tags` (`tag_id`, `name`) VALUES
(1, 'tag1'),
(2, 'tag2'),
(3, 'tag3'),
(4, 'tag4');



========================================


Оригинальный запрос с поиском наиболее популярных статей в каждой категории. Минус - выводит 2 статьи из одной категории если они имеют одинаковый рейтинг. Но это легко решается уже на стороне скрипта.


SELECT a.article_id, a.views
FROM articles AS a
JOIN (
SELECT category_id, max( views ) AS max_views
FROM articles
GROUP BY category_id
) AS v ON ( a.category_id = v.category_id )
WHERE a.views = v.max_views


===========


Задача - вывести статьи относящиеся к текущей статье на основе имеющихся тагов.

Сразу был отброшен вариант с "умным" поиском тагов, аля большинство статей с тагом А, так же имеют таг Б, возможно юзеру будет интересно что-то из тага Б. Возможно кто-то сможет реализовать и это, но мне кажется задача будет довольно сложной.


Сейчас делаю вот так (пример для статьи 1 из дампа выше)


explain select * from `articles` join (select article_id, count(*) as cnt from `art2tag` where tag_id in (1,2) group by article_id order by cnt desc limit 10) as t on t.article_id = `articles`.article_id
where articles.article_id != 1



Explain

1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3 Using where
1 PRIMARY articles eq_ref PRIMARY PRIMARY 4 t.article_id 1
2 DERIVED art2tag ALL NULL NULL NULL NULL 8 Using where; Using temporary; Using filesort
 

phprus

Moderator
Команда форума
Lifeline
Почему у тебя таблица art2tag совсем без индексов? Я бы сделал первичный индекс на оба поля для гарантирования уникальности пар. И возможно индекс по <`tag_id`, `article_id`> или просто по <`tag_id`> может ускорить внутренний подзапрос.
 

prolis

Новичок
Автор оригинала: Lifeline
Сразу был отброшен вариант с "умным" поиском тагов, аля большинство статей с тагом А, так же имеют таг Б, возможно юзеру будет интересно что-то из тага Б. Возможно кто-то сможет реализовать и это, но мне кажется задача будет довольно сложной.
вот запрос, который вернет рейтинг связанных тегов:
[sql]
select t1.tag_id, t2.tag_id, count(*) as cnt from art2tag t1, art2tag t2
where t1.article_id=t2.article_id
and t1.tag_id<>t2.tag_id
group by t1.tag_id, t2.tag_id
order by t1.tag_id, cnt desc
[/sql]
 

Lifeline

Новичок
prolis респект !

Правда например выберем для тага ИД 1


EXPLAIN SELECT t1.tag_id, t2.tag_id, count( * ) AS cnt
FROM art2tag t1, art2tag t2
WHERE t1.article_id = t2.article_id AND t1.tag_id <> t2.tag_id
and t2.tag_id = 1
GROUP BY t1.tag_id, t2.tag_id
ORDER BY t1.tag_id, cnt DESC




1 SIMPLE t2 index PRIMARY,article_id PRIMARY 8 NULL 8 Using where; Using index; Using temporary; Using f...
1 SIMPLE t1 ref PRIMARY,article_id PRIMARY 4 test_db.t2.article_id 1 Using where; Using index

-~{}~ 28.01.10 15:53:

Хотя не уверен что получится улучшить тк в любом случае надо пробежать всю таблицу..
 

prolis

Новичок
Lifeline
тут опять же несколько путей - оптимизировать выполнение, либо закешировать (вряд ли этот рейтинг в реальном времени переколбашивается)
для одно тега: [sql]
WHERE t1.article_id = t2.article_id and t1.tag_id = 1
AND t2.tag_id<>1

[/sql]
 

Lifeline

Новичок
prolis да. В принципе поиск по тагам не самая критичная задача.

Но например вытянуть просто самую популярную статью по опр тагу - опять же проблема по скорости...

если держать все в одной базе то получается что-то вроде


select ... from articles where tags like '%|tag1|%' order by views desc limit ..

то все работает быстрее, чем в варианте 3х таблиц.
 
Сверху