Я нахожусь теперь в заключительных этапах обновления дизайна иерархии в главной системе обработки транзакций, и я смотрел некоторое время на этот запрос с 150 строками (который я сэкономлю Вас вся скука чтения), и думая, что должен быть лучший путь.
Быстрая сводка вопроса следующие:
Я нашел несколько связанный вопрос, но это - действительно только приблизительно 20% ответа, в котором я на самом деле нуждаюсь. Вот полный сценарий/спецификация:
hierarchyid
(осуществленный путь), индексированный и в ширину и в глубину. Каждый узел/запись иерархии имеет a Name
столбец, который должен быть запрошен на. Запросы иерархии на основе узла чрезвычайно быстры, не волнуйтесь о тех.Моя "мечта" состоит в том, чтобы предоставить мгновенную обратную связь пользователю, как в прогрессивном поиске/фильтре, но я понимаю, что это может быть невозможно или чрезвычайно трудно. Я был бы доволен любым существенным улучшением по существующему методу, который обычно берет между 0,5 с к 1 с в зависимости от количества результатов.
Ради полноты существующий запрос (хранимая процедура) запускается путем сбора всех вершин, содержащих заключительный термин, затем присоединяется вверх и исключает любого, пути которого не соответствуют более ранним условиям. Если это кажется обратным кому-либо, пребывайте в уверенности, это более эффективно, чем запуск с корней и разветвление на выходе. Это было "старым" путем и могло легко занять несколько секунд на поиск.
Так мой вопрос снова: существует ли лучший (более эффективный) способ выполнить этот поиск?
Я не обязательно ищу код, просто подходы. Я рассмотрел несколько возможностей, но у них всех, кажется, есть некоторые проблемы:
NamePath
столбец, который является на самом деле вложенной последовательностью строк, с помощью типа CLR, подобного hierarchyid
самостоятельно. Проблема, я понятия не имею, как Microsoft может "перевести" запросы на этом типе для индексации операций, и я даже не уверен, возможно ли сделать на UDT. Если конечным результатом является просто полное индексное сканирование, я ничего не получил этим подходом.Это не действительно конец света, если я не могу добиться большего успеха, чем, что я уже имею; поиск "довольно быстр", никто не жаловался на это. Но я готов держать пари, что кто-то занялся этой проблемой прежде и имеет некоторые идеи. Совместно используйте их!
Привет, Ааррон, у меня следующая идея:
Судя по вашему описанию, у меня в голове следующее изображение:
Aaron
/ \
/ \
/ \
House Cars
| / \
Living Room Ferrari Mercedes
|
Liquor Cabinet
/ | \
Table Door Window
Вот как может выглядеть ваше дерево поиска. Теперь я бы сортировал узлы на каждом уровне:
Aaron
/ \
/ \
/ \
Cars House
/ \ /
/ \ /
/ \ /
/ \ /
/ X
/ / \
/ / \
/ / \
/ / \
| / \
| / \
Ferrari Living Room Mercedes
|
Liquor Cabinet
/ | \
Door Table Window
Теперь обработка запроса должна быть простой и быстрой:
Пусть будет M - количество общих совпадений (количество узлов, совпадающих с последним словом в запросе). Тогда наше время обработки: O( (log N)^2 + M * (log N) ):
.
Двоичный поиск занимает время O(log N) для каждого уровня, а уровни O(log N) существуют, поэтому мы должны потратить как минимум время O( (log N)^2). Теперь, для каждого совпадения, мы должны проверить, совпадает ли полный путь от нашего совпадающего узла до корня с полным запросом. Путь имеет длину O(log N). Таким образом, учитывая M совпадений в целом, мы проводим еще одно M * O(log N) время, таким образом, результирующее время выполнения - O( (log N)^2 + M * (log N) ).
Когда у вас мало совпадений, время обработки приближается к O( (log N)^2 ), что довольно неплохо. Наоборот, если происходит наихудший случай (каждый путь соответствует запросу (M = N)), время обработки приближается к O(N log N), что не слишком хорошо, но и не слишком вероятно.
Реализация:.
Ты сказал, что тебе нужна только идея. Далее мои знания о базах данных очень ограничены, поэтому я не буду здесь много писать, просто опишу некоторые идеи.
.
Таблица узлов может выглядеть следующим образом:
Эта таблица должна быть отсортирована по столбцу "Текст". Используя описанный выше алгоритм, sql запрос внутри цикла мог бы выглядеть следующим образом:
SELECT ID FROM node WHERE Level = $i AND Text LIKE $text
Надеюсь, вы меня поняли.
Еще больше ускорить процесс можно не только сортировкой таблицы по столбцу "Текст", но и комбинированными столбцами "Текст" и "Уровень", т.е. все записи внутри Level=20 отсортированы, все записи внутри Level=19 отсортированы и т.д.(но никакой общей сортировки по всей таблице не требуется). Впрочем, счетчик узлов PER LEVEL находится в O(N), поэтому асимптотического улучшения времени исполнения нет, но я думаю, что стоит попробовать, учитывая более низкие константы, которые вы получаете в реальности.
Я только что заметил, что итеративный алгоритм совершенно не нужен (таким образом, от информации об Уровне можно отказаться). Этого вполне достаточно, чтобы:
Это улучшает время выполнения до O(log N + M * (log N)).
.взгляните на Апача Лусена. Вы можете реализовать очень гибкий и в то же время эффективный поиск с помощью Lucene. Это может быть полезно.
Также посмотрите на шаблоны поиска - то, что вы описываете, может вписаться в шаблон Грановидного поиска.
Довольно легко реализовать тривиальный алгоритм "Живая дверь Аарона Хауса", но не уверен, что обычные алгоритмы, основанные на SVM/классификации/энтропии, масштабируются до большого массива данных. Возможно, вам также захочется взглянуть на концепции "поиска аппроксимации" Мотвани и Рагхавана.
Пожалуйста, отправьте назад то, что вы нашли, если это возможно :-)
.