2016-03-19 2 views
1

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

Имя файла может быть различным - длиной 10, 20, 50 или более символов. По крайней мере, на данный момент мой тестовый набор данных не содержит файлов с именами. Пользователь может выполнять частичный поиск, например, ищет «1001» должен вернуть файл с именем 10_1001_20_30_40_50.

Моя текущая структура таблицы:

CREATE TABLE `file` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
    `id_category` int(10) unsigned NOT NULL, 
    `filename` varchar(255) NOT NULL, 
    `file_ext` varchar(3) NOT NULL, 
    `date_added` timestamp NULL DEFAULT CURRENT_TIMESTAMP, 
    PRIMARY KEY (`id`,`id_category`), 
    KEY `idx_file_filename` (`filename`) USING BTREE, 
    KEY `fk_file_1_idx` (`id_category`), 
    FULLTEXT KEY `filename` (`filename`) 
) ENGINE=MyISAM AUTO_INCREMENT=24974 DEFAULT CHARSET=utf8; 

INSERT INTO `file` (`id`,`id_category`,`filename`,`file_ext`,`date_added`) VALUES (22474,14199,'095_98_1002_1003_148_98_1001_003','pdf','2016-03-19 19:02:12'); 
INSERT INTO `file` (`id`,`id_category`,`filename`,`file_ext`,`date_added`) VALUES (22475,14199,'095_98_1002_1003_148_98_1001_001','pdf','2016-03-19 19:02:11'); 

Я пытался использовать MATCH() AGAINST(), но оказалось, что это не очень хорошая идея, если у вас нет пробелов в строке и хотите do "if string содержит поиск":

SELECT id, filename FROM `file` WHERE MATCH(filename) AGAINST ('1002*' IN BOOLEAN MODE); 

Это не собирается возвращать то, что мне нужно. Что я рассматриваю это использование FULLTEXT раздельным всех имен файлов при импорте в 3 длины частей, разделенных пробелами и их использовать запросы, как это (мин пользователем длина строки может обеспечить.):

SELECT * FROM `file` WHERE MATCH(filename) AGAINST ('100*' IN BOOLEAN MODE); 

Конечно, я могу оставить имена файлов, как они есть, и использовать LIKE оператора:

SELECT * FROM `file` WHERE filename LIKE '%100%' 

но есть много негативных мнений по поводу использования LIKE для больших наборов данных. Мне интересно, будет ли мое решение с добавлением пробелов в имена файлов.

+0

Ale Вы ищете только 1002, или вам нравится искать более длинные последовательности (1002_1003) тоже? –

+0

Это может быть любой запрос> = 3 символа –

ответ

0

Попытка использовать FULLTEXT: требуется пространство, ограничивает вас (в основном) до полного «слов», становится неэффективным с «короткими» словами, промахов «стоп-слова» и т.д.

LIKE '%100%», хотя неэффективна потому, что он должен проверять каждую строку, это то, что вам нужно.

Вы подразумеваете, что все соответствующие части имен файлов являются цифрами? И что вы хотите протестировать только целые части? То есть 22_100_33 будет искать 22, 100 и 33, но не для 2, 10, 00, и т.д ?? Если все это так, то LIKE не будет работать правильно. Пример: 101_1000 будет улавливаться LIKE '%100% '.

Так, может быть вы хотите создать «инвертированный индекс»: Для 10_1001_20_30_40_50, вы бы иметь 6 строк в таблице: 10, 1001, и т.д., а также в остальные столбцы, или какой-либо идентификатор (s) для присоединения к таблице file.

+0

Спасибо за освобождение чека с FT. Я буду проверять детали, и мне нужны детали назад, так что все в порядке. Имена файлов и их части могут быть буквенно-цифровыми, различной длины, поэтому я не могу использовать инвертированную структуру индекса, которую вы предложили. Вопрос по-прежнему открыт - на данный момент похоже, что я должен использовать LIKE. –

0

есть много негативные мнения по поводу использования LIKE для больших наборов данных

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

Если вы действительно хотите ускорить его, я могу подумать об одном варианте, но жертвы будут огромными - память, время вставки, универсальность, гибкость, сложность ... Вы можете построить «инвертированный индекс» для суффиксов.Таблица будет выглядеть (псевдокод):

CREATE TABLE Pref(
    prefix varchar(255) NOT NULL, 
    fileid bigint(20) unsigned NOT NULL, 

CONSTRAINT [PK_Pref] PRIMARY KEY CLUSTERED 
(
    prefix ASC, 
    fileid ASC 
)) 

и есть данные, как этот

'095_98_1002_1003_148_98_1001_003', 22474 
'95_98_1002_1003_148_98_1001_003', 22474 
'5_98_1002_1003_148_98_1001_003', 22474 
'_98_1002_1003_148_98_1001_003', 22474 
'98_1002_1003_148_98_1001_003', 22474 
... 
'03', 22474 
'3', 22474 

было бы кластерном первичный ключ на обеих колонках. Таким образом, это будет упорядочено префиксом, и вы можете изменить поиск infix '%abcd%' в префиксный поиск 'abcd%'. Тогда запрос будет иметь форму

SELECT id, filename FROM `file` 
WHERE id IN (SELECT fileid FROM Pref WHERE prefix like 'abcd%') 

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

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