Общий алгоритм работы текстового индекса при выборке

  1. Запрос разбивается на слова

  2. Для каждого слова (term) формируется список вариантов слова (subTerm):

    • слово;
    • транслит;
    • неправильная раскладка;
    • синонимы.
    • опечатки (пропуски/перестановки букв)
    • слово, полученное путём соединения с предыдущим термом (для него для него также применяются остальные механизмы получения вариантов) Эти варианты пропускаются через стеммер и список варианов дополняется корнями слов.
  3. Далее для каждого subTerm производится поиск в суффиксном дереве. На выходе получается структура вида:

   vectorTerm<                                                 | индекс - номер слова в запросе
	vectorSubTerm<                                         | subTerms
		vectorDocInfo<                                 | набор документов соответствующий данному subTerm
			vdocId,vector<                         | идентификатор документа и
					subTermPositionInDoc>  | набор позиций данного subTerm в документе с данным идентификатором
			>                                      |
		>                                              |
	>                                                      |

Позиции слова в документа исчисляются в номерах слов. Позиция включает номер поля. 4. Далее для каждого терма или фразы производится вычисление логических операций

  • oneOf
  • mustPresent
  • notPresent

Данное вычисление основывается на статусном массиве документов. Фактически происходит проход по всем документам результатов и в массиве выставляется статус (не участвует(0), исключен(-1), удовлетворяет критериям). Для оптимизации памяти набор документов ограничен mergeLimit. Вся информация о статусе документа хранится в разряженном массиве merged и merged_rd и vectorAreas. Массив merged адрессуется значением из массива idoffsets размер которого равен колличеству документов. Массив merged_rd адрессуется полем indexAdd хранящимся внутри merged. Массив vectorAreas адрессуется полем areaIndex хранящимся в merged. Раздельное хранение данных дает существенный выигрыш в производительности (~10-15%).

Для слов фразы происходит отдельное вычисление удовлетворяющих документов. Для слов внутри фразы действует операция mustPresent. Определение принадлежности слова группе основывается на номере группы из запроса (FtDslOpts.groupNum). Булева флага тут не достаточно, так как группы могут идти подряд “group1 group11” “group2 group22”.

Стоит подчеркнуть, что расстояния между словами (term) для слов внутри группы вычисляются иначе нежели для слов вне группы. Для слов вне группы, где расстояние используется для подсчета релевантности, используются только позиции самого релевантного subTerm. Для группы формируется полный список позиций всех subTerm предыдущего term (MergedIdRelEx.posTmp) для вычисления расстояния с позициями текущего term. Для вычисления расстояния расстояния используется массив MergedIdRel.cur. Поле MergedIdRel.next хранит позиции subTerm c самой высокой релевантностью.

Для подсвечивания позиции фразы приходится формировать дополнительный вектор позиций всех слов фразы MergedIdRelExArea.wordPosForChain. вместе с позициям в этом векторе хранятся связи с годными (удовлетворяющими условию расстояния) позициями предыдущего слова (pair.second). С помощью обратного прохода по ссылкам удается выбрать только необходимые слова предыдущего уровня.