Улучшение путь_к_файлу поиск в MySQL

у меня есть несколько миллионов имен файлов, которые мне нужно найти. Они выглядят так:

LG_MARGINCALL_HD2CH_127879834_EN.mov

Если кто-то ищет любое из следующего, он должен соответствовать:

  • рентабельность
  • margin call
  • margin call mov
  • margin call hd en
  • margin call hd en mov

то, что я сейчас использую, - это mysql %LIKE% search. Что-то вроде:

SELECT filename FROM path WHERE filename LIKE '%margin%' AND filename LIKE '%mov%'

Это смертельно медленно (может иметь до десяти секунд для поиска). Заметьте, что это работает хотя.

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

6 ответов


ваша стратегия поиска, как вы заметили, медленно. Это медленно, потому что

 LIKE '%something%'

должен сканировать таблицу, чтобы найти совпадения. Ведущий % подписывается на LIKE поиск-отличный способ разрушить производительность.

Я не знаю, сколько столбцов в вашей path таблица. Если есть много столбцов вы можете сделать две быстрые вещи, чтобы улучшить производительность:

  1. избавиться SELECT * и список имен столбцов, которые вы хотите в ваш набор.
  2. создать составной индекс, состоящий из вашего filename столбец, за которым следуют другие столбцы, которые вам нужно получить.

(это не поможет, если только у вас есть несколько столбцов в таблице.)

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

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

первый, создайте новую таблицу под названием "searchterm", содержащую

 filename_id INT   the id number of a row in your path table
 searchterm  VARCHAR(20)  a fragment of a filename.

во-вторых, напишите программу, которая читает filename_id и filename значения, и вставляет кучу разных строк для каждого в searchterm. Для элемента, который вы показали, значения должны быть:

LG_MARGINCALL_HD2CH_127879834_EN.mov   (original)
LG  MARGINCALL  HD2CH  127879834  EN  mov   (split on punctuation)
 HD 2 CH                                    (split on embedded numerics)
 MARGIN CALL                                (split on an app-specific list of words)

Итак, у вас будет куча записей в таблице searchterm, все с одинаковыми filename_id значение и много разных кусочков текста.

наконец, при поиске вы можете сделать этот.

 SELECT path.id, path.filename, path.whatever,
        COUNT(DISTINCT searchterms.term) AS termcount
   FROM path
   JOIN searchterm ON path.filenanme_id = search.filename_id
  WHERE searchterm.term  IN ('margin','call','hd','en', 'mov')
  GROUP BY path.id, path.filename, path.whatever
  ORDER BY path.filename, COUNT(DISTINCT searchterms.term) DESC

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

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


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

есть несколько решений, которые могут ответить на это, один из лучших на данный момент Эластичный Поиск.

Он имеет все возможности для обработки полнотекстового поиска в реальном времени. И это выходит во многом за рамки этого, предоставляя авто-предложения, автозаполнение и т. д.

и это с открытым исходным кодом.


прекратите использовать оператор like вместо использования match() и используйте полнотекстовый индекс для столбца поиска, и ваша таблица должна быть MYISAM(я не знаю, является ли это или нет)


Я предлагаю 2 вещи, чтобы попытаться улучшить производительность. 1-й-использовать ключевое слово объяснить перед select. Это может дать вам некоторую помощь о медленной производительности запроса. Но я думаю, что это не очень поможет. 2-я вещь-использовать REGEXP. Пример всего этого:

EXPLAIN SELECT filename FROM path WHERE filename LIKE REGEXP '^.*MAR{1}.*mov{1}'

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


попробуйте использовать SPHINX для полнотекстового поиска. http://sphinxsearch.com/


Это может быть быстрее, чем при использовании AND:

SELECT filename FROM path WHERE filename LIKE '%margin%call%hd%en%mov%'

но наличие " % "в начале строки всегда будет замедлять его.

вы должны использовать полнотекстовый индекс поиска в поле, а затем использовать что-то вроде:

SELECT filename FROM path WHERE MATCH(filename) AGAINST('+margin +call +hd +en +mov' IN BOOLEAN MODE);