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

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

У кого-нибудь есть какие-либо идеи?


Люди неправильно поняли мой вопрос:

Как подсчитать количество таких вхождений в одной строке?


person stalepretzel    schedule 28.12.2008    source источник


Ответы (9)


Это не то, в чем реляционные базы данных очень хороши, если только вы не можете использовать полнотекстовое индексирование, а вы уже заявили, что не можете, поскольку используете InnoDB. Я бы предложил выбрать соответствующие строки и выполнить подсчет слов в коде приложения.

person Alison R.    schedule 16.02.2010

Вы можете попробовать этот извращенный способ:

SELECT 
(LENGTH(field) - LENGTH(REPLACE(field, 'word', ''))) / LENGTH('word') AS `count`
ORDER BY `count` DESC
  • Этот запрос может быть очень медленным
  • Это выглядит довольно некрасиво
  • REPLACE() чувствителен к регистру
person Slava Popov    schedule 16.02.2010
comment
При этом будут учитываться строки, а не слова. - person RandomSeed; 12.06.2014

Вы можете решить проблему чувствительной к регистру функции mysql REPLACE(), используя LOWER().

Это небрежно, но с моей стороны этот запрос выполняется довольно быстро.

Чтобы ускорить процесс, я получаю набор результатов в выборе, который я объявил как производную таблицу в своем «внешнем» запросе. Поскольку mysql уже имеет результаты на этом этапе, метод replace работает довольно быстро.

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

SELECT DISTINCT ( 
((length(x.ent_title) - length(replace(LOWER(x.ent_title),LOWER('there'),''))) / length('there')) 
+ ((length(x.ent_content) - length(replace(LOWER(x.ent_content),LOWER('there'),''))) / length('there'))
 + ((length(x.ent_title) - length(replace(LOWER(x.ent_title),LOWER('another'),''))) / length('another')) 
+ ((length(x.ent_content) - length(replace(LOWER(x.ent_content),LOWER('another'),''))) / length('another')) 
) as relevance, 
x.ent_type, 
x.ent_id, 
x.this_id as anchor,
page.page_name
FROM ( 
(SELECT 
'Foo' as ent_type, 
sp.sp_id as ent_id, 
sp.page_id as this_id, 
sp.title as ent_title, 
sp.content as ent_content,
sp.page_id as page_id
FROM sp
WHERE (sp.title LIKE '%there%' OR sp.content LIKE '%there%' OR sp.title LIKE '%another%' OR sp.content LIKE '%another%' ) AND (sp_content.title NOT LIKE '%goes%' AND sp_content.content NOT LIKE '%goes%')
) UNION (
  [search a different table here.....]
)
) as x
JOIN page ON page.page_id = x.page_id 
WHERE page.rstatus = 'ACTIVE'
ORDER BY relevance DESC, ent_title;

Надеюсь, это поможет кому-то

-- Seacrest вне

person user423443    schedule 17.08.2010
comment
При этом будут учитываться строки, а не слова. - person RandomSeed; 12.06.2014

создайте пользовательскую функцию, подобную этой, и используйте ее в своем запросе.

DELIMITER $$

CREATE FUNCTION `getCount`(myStr VARCHAR(1000), myword VARCHAR(100))
    RETURNS INT
    BEGIN
    DECLARE cnt INT DEFAULT 0;
    DECLARE result INT DEFAULT 1;

    WHILE (result > 0) DO
    SET result = INSTR(myStr, myword);
    IF(result > 0) THEN 
        SET cnt = cnt + 1;
        SET myStr = SUBSTRING(myStr, result + LENGTH(myword));
    END IF;
    END WHILE;
    RETURN cnt;    

    END$$

DELIMITER ;

Надеюсь, это поможет >Ссылаться на это

person Akhil    schedule 26.07.2013

Что-то вроде этого должно работать:

выберите count(*) из таблицы, где имя поля REGEXP '[[:‹:]]слово[[:>:]]';

Подробности в руководстве по MySQL, раздел 11.4.2.

person Alex    schedule 28.12.2008
comment
Это проверяет, сколько строк содержит строку поиска. Спрашивающий хочет подсчитать, как часто искомая строка содержится в каждой строке. - person flu; 20.01.2014

Что-то вроде LIKE или REGEXP не будет масштабироваться (если только это не совпадение крайнего левого префикса).

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

select count(*) from yourtable where match(title, body) against ('some_word');
person ʞɔıu    schedule 28.12.2008
comment
Не могу сделать полнотекстовый индекс... Я использую InnoDB. - person stalepretzel; 28.12.2008

Я использовал технику, как описано в ссылке ниже. Метод использует length и replace функции MySQL.

Релевантность ключевого слова

person Rishi Agarwal    schedule 29.12.2008

Если вам нужен поиск, я бы посоветовал что-то вроде Sphinx или Lucene, я считаю Sphinx (как независимый полнотекстовый индексатор) намного проще в настройке и запуске. Он работает быстро и очень быстро генерирует индексы. Даже если бы вы использовали MyISAM, я бы предложил использовать его, поскольку он имеет гораздо больше возможностей, чем полнотекстовый индекс MyISAM.

Он также может интегрироваться (несколько) с MySQL.

person Paul    schedule 04.12.2010

Это зависит от того, какую СУБД вы используете, некоторые позволяют писать UDF, которые могут это делать.

person wlk    schedule 17.08.2010