Сортировка MySQL по количеству вхождений

я делаю поиск в двух текстовых полях под названием Subject и Text для определенного ключевого слова. Для этого я использую LIKE заявление. Я столкнулся с проблемой при попытке отсортировать результаты по количеству повторений.

мой поисковый запрос выглядит так:

SELECT * FROM Table WHERE (Text LIKE '%Keyword%' OR Subject LIKE '%Keyword%')

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

здесь запрос с указанием граф:

SELECT *, COUNT(Text LIKE '%Keyword%') AS cnt FROM News WHERE (Text LIKE '%Keyword%' OR Subject LIKE '%Keyword%') ORDER BY cnt

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

3 ответов


ниже запрос может дать вам нет.вхождений строки появляется в обоих столбцах i.e текст и тема и будет сортировать результаты по критериям, но это не будет хорошей производительностью решения, лучше сортировать результаты на уровне кода приложения

SELECT *,
(LENGTH(`Text`) - LENGTH(REPLACE(`Text`, 'Keyword', ''))) / LENGTH('Keyword')
+
(LENGTH(`Subject`) - LENGTH(REPLACE(`Subject`, 'Keyword', ''))) / LENGTH('Keyword') `occurences`
 FROM 
`Table`
 WHERE (Text LIKE '%Keyword%' OR Subject LIKE '%Keyword%')
ORDER BY `occurences`  DESC

Скрипка Демо

предложил @lserni более чистый способ расчета вхождений

SELECT *,
(LENGTH(`Text`) - LENGTH(REPLACE(`Text`, 'test', ''))) / LENGTH('test') `appears_in_text`,

(LENGTH(`Subject`) - LENGTH(REPLACE(`Subject`, 'test', ''))) / LENGTH('test') `appears_in_subject`,

(LENGTH(CONCAT(`Text`,' ',`Subject`)) - LENGTH(REPLACE(CONCAT(`Text`,' ',`Subject`), 'test', ''))) / LENGTH('test') `occurences`
 FROM 
`Table1`
 WHERE (TEXT LIKE '%test%' OR SUBJECT LIKE '%test%')
ORDER BY `occurences`  DESC

Скрипка Демо 2


вы хотите SUM вместо. Count подсчитает, сколько записей имеют ненулевые значения, что означает, что будут подсчитаны все совпадения и несоответствия.

SELECT *, SUM(Text LIKE '%Keyword') AS total_matches
...
ORDER BY total_matches

SUM() подсчитает, сколько булевых истинных результатов производит подобное, которое будет типично для целых чисел, поэтому вы получите результат, подобный 1+1+1+0+1 = 4, вместо 5 не-нулей.


// escape $keyword for mysql
$keyword = strtolower('Keyword');
// now build the query
$query = <<<SQL
    SELECT *,
    ((LENGTH(`Subject`) - LENGTH(REPLACE(LOWER(`Subject`), '{$keyword}', ''))) / LENGTH('{$keyword}')) AS `CountInSubject`,
    ((LENGTH(`Text`) - LENGTH(REPLACE(LOWER(`Text`), '{$keyword}', ''))) / LENGTH('{$keyword}')) AS `CountInText`
    FROM `News`
    WHERE (`Text` LIKE '%{$keyword}%' OR `Subject` LIKE '%{$keyword}%')
    ORDER BY (`CountInSubject` + `CountInText`) DESC;
SQL;

возвращает количество вхождений в каждом поле и виды на что.

на 'keyword' должен быть ниже, чтобы это работало. Я не думаю, что это действительно быстро, производительность мудрая, поскольку она должна быть строчными полями, и нет никакого поиска без учета регистра в MySQL afaik.

вы можете индексировать каждый news элемент (subject и text) по словам и хранить в другой таблице с news_id и отсчет возникновения и после этого спичка против что.