2015-01-16 3 views
2

У меня есть база данных SQL с музыкальными композициями. У каждой песни, конечно, есть художник, альбом и жанр. У них также есть общий счетчик «популярности», который был получен из внешнего источника. Тем не менее, я хочу дать пользователям возможность проголосовать и за песни. В конце концов, результаты поиска должны быть упорядочены по этой популярности, а также точность результатов с исходным запросом.Как сортировать и фильтровать поиск по нескольким полям в SQL

Текущий запрос я использую следующим образом:

SELECT * 
FROM p2pm_tracks 
WHERE 
`artist` LIKE '%$searchquestion%' OR 
`genres` LIKE '%$searchquestion%' OR 
`trackname` LIKE '%$searchquestion%' OR 
`album_name` LIKE '%$searchquestion%' 
ORDER BY `popularity` DESC 
LIMIT $startingpoint, $resultsperpage 

борюсь со следующим:

  1. Пользователи ищут что-то. Я смотрю во всех полях: песня название, художник, альбом и жанр. Однако обычно определенный поисковый запрос содержит (части) несколько этих треков.

Например, пользователь может найти Opening Philip Glass.

В этом случае первого словом является названия песни, а второе и третье слова названия художника.

Другой пример:

Если я разбить запрос на пространствах, правильные следы найдены. Однако, если другой трек, который соответствует только одному из этих слов, имеет большую популярность, он будет возвращен до того, который действительно точно соответствует поисковому запросу.

Я по-прежнему хочу сортировать результаты таким образом, чтобы вещи, которые соответствуют более крупным частям запроса, находятся на вершине. Как я могу это сделать с помощью SQL?

  1. У меня статическая популярность и вы хотите создать новую. Поэтому я хочу использовать среднее количество всех голосов на определенном треке (эти голоса хранятся в другой таблице), за исключением случаев, когда голоса еще нет. Как я могу построить SQL-запрос, который делает это?

Мое приложение построено в PHP, но я хотел бы сделать как можно больше этого в SQL, предпочтительно в качестве нескольких запросов, как это возможно, чтобы уменьшить время ожидания.

Любая помощь будет оценена по достоинству.

+4

SQL - это не лучший способ добиться этого. Текстовая поисковая система (например, Solr Lucene) является гораздо лучшим способом, особенно если вы разрешаете поиск, например, «открытие стеклянного стекла». Некоторые РСУБД (например, SQL Server) имеют встроенные полнотекстовые двигатели и могут быть подходящими. –

+0

Также обратите внимание, что ваш запрос MySQL сейчас уязвим для SQL-инъекции таким образом. Всегда избегайте ваших запросов. –

+0

Вы можете сортировать его на стороне сервера, используя levenstein http://php.net/manual/en/function.levenshtein.php – Ruben

ответ

4

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

Вот код:

SELECT *, 
    CASE WHEN `artist` LIKE '%$searchquestion%' THEN 1 ELSE 0 END AS artist_match, 
    CASE WHEN `genres` LIKE '%$searchquestion%' THEN 1 ELSE 0 END AS genres_match, 
    CASE WHEN `trackname` LIKE '%$searchquestion%' THEN 1 ELSE 0 END AS trackname_match, 
    CASE WHEN `album_name` LIKE '%$searchquestion%' THEN 1 ELSE 0 END AS album_name_match, 
FROM p2pm_tracks 
WHERE 
`artist` LIKE '%$searchquestion%' OR 
`genres` LIKE '%$searchquestion%' OR 
`trackname` LIKE '%$searchquestion%' OR 
`album_name` LIKE '%$searchquestion%' 
ORDER BY 
`artist_match` DESC, 
`genres_match` DESC, 
`trackname_match` DESC, 
`album_name_match` DESC, 
`popularity` DESC, 
LIMIT $startingpoint, $resultsperpage 

Этот запрос будет собирать результаты, связанные с:

  • художник FIRST,
  • ТОГДА жанр,
  • ТОГДА название трека,
  • THEN Название альбома,
  • ТОГДА популярность песни

Чтобы оптимизировать этот запрос, вы должны избегать с помощью «LIKE» и использовать «полнотекстовой поиск» вместо этого.

Оптимизированный код будет:

SELECT *, 
    CASE WHEN MATCH (artist) AGAINST ('$searchquestion') THEN 1 ELSE 0 END AS artist_match, 
    CASE WHEN MATCH (genres) AGAINST ('$searchquestion') THEN 1 ELSE 0 END AS genres_match, 
    CASE WHEN MATCH (trackname) AGAINST ('$searchquestion') THEN 1 ELSE 0 END AS trackname_match, 
    CASE WHEN MATCH (album_name) AGAINST ('$searchquestion') THEN 1 ELSE 0 END AS album_name_match, 
FROM p2pm_tracks 
WHERE 
MATCH (artist) AGAINST ('$searchquestion') OR 
MATCH (genres) AGAINST ('$searchquestion') OR 
MATCH (trackname) AGAINST ('$searchquestion') OR 
MATCH (album_name) AGAINST ('$searchquestion') 
ORDER BY 
`artist_match` DESC, 
`genres_match` DESC, 
`trackname_match` DESC, 
`album_name_match` DESC, 
`popularity` DESC, 
LIMIT $startingpoint, $resultsperpage 

И убедитесь, что вы используете MyISAM двигатель для таблицы MySQL и что вы создали индексы для столбцов, которые вы хотите искать. Код для таблицы MySQL должен выглядеть следующим образом:

CREATE TABLE p2pm_tracks (
    id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, 
    artist VARCHAR(255) NOT NULL, 
    trackname VARCHAR(255) NOT NULL, 
    ... 
    ... 
    FULLTEXT (artist,trackname) 
) ENGINE=MyISAM; 

Для получения дополнительной информации, проверьте следующее: - http://dev.mysql.com/doc/refman/5.0/en/fulltext-natural-language.html - http://dev.mysql.com/doc/refman/5.5/en/fulltext-boolean.html

Если вы ищете что-то более продвинутое, а затем посмотреть в Solr (на основе Lucene), Sphinx, ElasticSearch (на основе Lucene) и т. д.

+0

Спасибо! Это помогает много. Очень хорошо знать, что можно сортировать результаты таким образом :-) – Qqwy

0

Хм, в соответствии с вашим 1. пример сложный в SQL, я не уверен, есть ли функция. то, что вам нужно, это что-то вроде этого Funktion в PHP

http://php.net/manual/function.similar-text.php

Или выберите в ваш запрос только в среднем голосования и вычислить, как «хорошие» результаты матчей с помощью PHP и функцию аналогичного текста.

1

MySQL не так хорош в поиске текста :(

  1. Что вы могли бы попытаться сделать, это посмотреть на полную функциональность поиска текста (http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html)

  2. С матчем с функцией вы можете получить уместность, где вы можете заказать на.

    SELECT, p2pm_tracks. *, MATCH (исполнитель, жанры) ПРОТИВ ('некоторые слова'), как отношение, MATCH (художник) ПРОТИВ («несколько слов») AS artist_relevance

1

Пожалуйста, не используйте LIKE. Это очень медленно. Вы можете использовать полнотекстовый поиск в mysql, но вы не можете определить, какой столбец является более важным.

Лучшее решение - mysql со сфинксом.

Смежные вопросы