Основная поисковая оптимизация данных - PullRequest
6 голосов
/ 15 июля 2011

Я работаю над функцией поиска в одном из моих приложений на основе Core Data и пытаюсь собрать все советы по оптимизации поиска, чтобы получить ее как можно быстрее. Поиск должен быть достаточно быстрым, чтобы он мог выдавать почти мгновенные результаты для базы данных из 20 000+ объектов.

Что я сделал до сих пор (насколько оптимизация идет)

  • Реализован метод, показанный в сеансе WWDC 2010, 137, создание ключевого объекта и создание отношения ко многим из моих основных объектов. Атрибут name ключевого объекта индексируется, и ключевые слова создаются во время начальной процедуры импорта путем разделения соответствующих строк в основных объектах и ​​их нормализации (без учета регистра и диакритических знаков)
  • Использование >= и < двоичных компараторов вместо BEGINSWITH и т. Д. Мой формат предиката:

SUBQUERY(keywords, $keyword, ($keyword.name >= $LB) AND ($keyword.name < $UB)).@count != 0

Где $LB - строка нижних границ, а $UB - верхние границы. Я создаю составной предикат AND, используя этот формат и массив поисковых терминов.

Прямо сейчас я выполняю выборку один раз (когда пользователь печатает первую букву), используя размер пакета выборки около 20, а затем сужаю результаты поиска, используя метод NSArray -filteredArrayUsingPredicate, поскольку они продолжают печатать. Я также предварительно выбираю отношение keywords, потому что оно используется для фильтрации. Часть, которая занимает больше всего времени, очевидно, является начальной выборкой. Заметная задержка ~ 1-2 с в библиотеке из 15 000 объектов. Профилирование времени показывает, что задержка вызывает именно выборка:

http://cl.ly/3a1b2022452M2V323f2H

Еще одна вещь, на которую стоит обратить внимание, это то, что мне нужно выбрать несколько объектов для результатов. У всех сущностей есть атрибут ranking, но я не могу выбрать более одного одновременно, поэтому я вынужден извлекать их отдельно, объединять в один массив и затем сортировать вручную с помощью -sortedArrayUsingDescriptors.

Любые советы о том, как ускорить это, будут с благодарностью.

РЕДАКТИРОВАТЬ: на основе предложений @ImHuntingWabbits:

После добавления объекта KeywordFirstChar моя модель данных (упрощенная) будет выглядеть следующим образом:

new model

Теперь возникает вопрос как мне написать предикат для Car сущности, который выбирает на основе KeywordFirstChar? Единственное, о чем я могу думать, это:

SUBQUERY(keywords, $keyword, $keyword.firstChar.char == %@), где %@ - это символ для поиска, но я не знаю, как это будет намного эффективнее, учитывая, что он все равно должен перечислять более keywords, если только я не неверно истолковал предложения.

1 Ответ

4 голосов
/ 15 июля 2011

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

Вы по-прежнему сканируете 15 тыс. Записей на предмет попадания первого символа и, вероятно, сопоставляете их с большим количеством.

Выможет дополнительно оптимизировать его, проиндексировав индекс ключевого слова, создав две новые сущности:

  • KeywordFirstChar
  • KeywordFirstTwoChars

Оба с отношением ко-многим кключевые слова, на которые они указывают.

if (searchPredicate.length == 1) {
    //search on KeywordFirstChar
} else if (searchPredicate.length == 2) {
    //search on KeywordFirstTwoChars
} else {
    //search on keyword
}

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

Редактирование (извлечение объекта):

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

 [fetchRequest setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObject:@"keyword.sourceObject"]];

Где ключевое слово - это отношение к сущности Keyword, а sourceObject - это объект, который вы хотите в конечном итоге получить.

Edit (Predicate):

Предикат по сути тот же, просто измените имена, чтобы они соответствовали новому объекту (имя может не соответствовать имени, вместо firstChar или некоторому другому свойству).

...