Перейти к содержанию

Функции ArangoSearch

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

Операция AQL SEARCH принимает поисковые выражения, такие как PHRASE(doc.text, "foo bar", "text_en"), для запроса представлений. Вы можете комбинировать функции фильтра и контекста ArangoSearch, а также операторы AND и OR для формирования сложных условий поиска. Аналогично, операция FILTER принимает такие поисковые выражения при использовании инвертированных индексов.

Функции подсчета баллов позволяют ранжировать совпадения и сортировать результаты по релевантности. Они ограничены функцией Views.

Функции подсветки поиска позволяют получить позиции строк совпадений. Они ограничены представлениями.

Большинство функций можно использовать и без инвертированного индекса или без представления и ключевого слова SEARCH, но тогда они не ускоряются индексом.

Контекстные функции

ANALYZER()

ANALYZER(expr, analyzer) → retVal

Устанавливает анализатор для заданного поискового выражения.

Функция ANALYZER() применима только для запросов к представлениям arangosearch.

В запросах к представлениям search-alias и инвертированным индексам не нужно указывать анализаторы, так как каждое поле может быть проиндексировано только одним анализатором, и они выводятся из определения индекса.

Анализатором по умолчанию является identity для любого поискового выражения, которое используется для фильтрации представлений arangosearch. Эта служебная функция может быть использована для обертывания сложного выражения для установки определенного анализатора. Она также устанавливает его для всех вложенных функций, которым требуется такой аргумент, чтобы избежать повторения параметра Analyzer. Если аргумент Analyzer передается во вложенную функцию независимо, то он имеет приоритет над Analyzer, установленным через ANALYZER().

Функция TOKENS() является исключением. Она требует передачи имени анализатора во всех случаях, даже если обернута в вызов ANALYZER(), поскольку это не функция ArangoSearch, а функция регулярной строки, которая может использоваться вне операций SEARCH.

  • expr (выражение): любое допустимое поисковое выражение
  • analyzer (строка): имя Analyzer.
  • возвращает retVal (любой): результат выражения, который он обертывает.

Пример: Использование пользовательского анализатора

Предположим определение представления с анализатором, имя и тип которого delimiter:

1
2
3
4
5
6
7
8
9
{
    "links": {
        "coll": {
            "analyzers": ["delimiter"],
            "includeAllFields": true
        }
    }
    // ...
}

... со свойствами анализатора {"delimiter": "|" } и примером документа { "text": "foo|bar|baz" } в коллекции coll, следующий запрос вернет документ:

1
2
3
FOR doc IN viewName
  SEARCH ANALYZER(doc.text == "bar", "delimiter")
  RETURN doc

Выражение doc.text == "bar" должно быть обернуто ANALYZER(), чтобы установить анализатор на delimiter. В противном случае выражение будет оценено с помощью анализатора по умолчанию identity. "foo|bar|baz" == "bar" не будет соответствовать, но View даже не обрабатывает индексированные поля с помощью анализатора identity. Следующий запрос также вернет пустой результат из-за несоответствия анализатора:

1
2
3
4
FOR doc IN viewName
  SEARCH doc.text == "foo|bar|baz"
  //SEARCH ANALYZER(doc.text == "foo|bar|baz", "identity")
  RETURN doc

Пример: Установка контекста анализатора с ANALYZER() и без него

В приведенном ниже запросе поисковое выражение подменяется ANALYZER() для установки анализатора text_en для обеих функций PHRASE():

1
2
3
FOR doc IN viewName
  SEARCH ANALYZER(PHRASE(doc.text, "foo") OR PHRASE(doc.text, "bar"), "text_en")
  RETURN doc

Без использования ANALYZER():

1
2
3
FOR doc IN viewName
  SEARCH PHRASE(doc.text, "foo", "text_en") OR PHRASE(doc.text, "bar", "text_en")
  RETURN doc

Пример: Приоритет анализатора и особенности функции TOKENS()

В следующем примере ANALYZER() используется для установки анализатора text_en, но при втором вызове PHRASE() устанавливается другой анализатор (identity), который отменяет ANALYZER(). Поэтому для поиска фразы foo используется анализатор text_en, а для поиска bar - анализатор identity:

1
2
3
FOR doc IN viewName
  SEARCH ANALYZER(PHRASE(doc.text, "foo") OR PHRASE(doc.text, "bar", "identity"), "text_en")
  RETURN doc

Несмотря на обертывающую функцию ANALYZER(), имя анализатора не может быть опущено в вызовах функции TOKENS(). Оба вхождения text_en необходимы, чтобы установить анализатор для выражения doc.text IN ... и для самой функции TOKENS(). Это связано с тем, что функция TOKENS() является функцией регулярной строки, которая не учитывает контекст анализатора:

1
2
3
FOR doc IN viewName
  SEARCH ANALYZER(doc.text IN TOKENS("foo", "text_en"), "text_en")
  RETURN doc

BOOST()

BOOST(expr, boost) → retVal

Переопределяет boost в контексте поискового выражения с заданным значением, делая его доступным для функций scorer. По умолчанию контекст имеет значение boost, равное 1.0.

  • expr (выражение): любое допустимое поисковое выражение.
  • boost (число): числовое значение boost
  • возвращает retVal (любой): результат выражения, который он обертывает.

Пример: Усиление поискового подвыражения

1
2
3
4
5
FOR doc IN viewName
  SEARCH ANALYZER(BOOST(doc.text == "foo", 2.5) OR doc.text == "bar", "text_en")
  LET score = BM25(doc)
  SORT score DESC
  RETURN { text: doc.text, score }

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

1
2
3
4
5
{ "text": "foo bar" }
{ "text": "foo" }
{ "text": "bar" }
{ "text": "foo baz" }
{ "text": "baz" }

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[
    {
        "text": "foo bar",
        "score": 2.787301540374756
    },
    {
        "text": "foo baz",
        "score": 1.6895781755447388
    },
    {
        "text": "foo",
        "score": 1.525835633277893
    },
    {
        "text": "bar",
        "score": 0.9913395643234253
    }
]

Функции фильтрации

EXISTS()

Если вы используете представления arangosearch, функция EXISTS() будет находить значения, только если вы установили свойство ссылки storeValues на "id" в определении представления (по умолчанию "none").

Проверка наличия атрибута

EXISTS(path)

Искать документы, в которых присутствует атрибут path.

  • path (выражение пути атрибута): атрибут для проверки в документе.
  • ничего не возвращает: функция оценивает булево значение, но это значение не может быть возвращено. Функция может быть вызвана только в выражении поиска. При ее использовании вне операции SEARCH или операции FILTER, использующей инвертированный индекс, выдается ошибка.
1
2
3
FOR doc IN viewName
  SEARCH EXISTS(doc.text)
  RETURN doc

Тестирование на тип атрибута

EXISTS(path, type)

Искать документы, в которых атрибут по адресу path присутствует и имеет указанный тип данных.

  • path (выражение пути атрибута): проверяемый атрибут в документе
  • type (строка): тип данных для проверки, может быть одним из:
    • null
    • "bool" / "boolean"
    • числовой
    • тип (соответствует значениям null, boolean и numeric)
    • строка
    • анализатор (см. ниже)
  • ничего не возвращает: функция оценивает булево значение, но это значение не может быть возвращено. Функция может быть вызвана только в поисковом выражении. Она выдает ошибку, если используется вне операции SEARCH или операции FILTER, использующей инвертированный индекс.
1
2
3
FOR doc IN viewName
  SEARCH EXISTS(doc.text, "string")
  RETURN doc

Тестирование на состояние индекса анализатора

EXISTS(path, "analyzer", analyzer)

Искать документы, в которых атрибут по адресу path присутствует и был проиндексирован указанным анализатором.

  • path (выражение пути атрибута): проверяемый атрибут в документе
  • type (string): строковый литерал анализатор.
  • analyzer (string, опционально): имя анализатора. Использует анализатор обертывающего вызова ANALYZER(), если не указан, или по умолчанию используется "identity".
  • ничего не возвращает: функция оценивает булево значение, но это значение не может быть возвращено. Функция может быть вызвана только в поисковом выражении. При ее использовании вне операции SEARCH или операции FILTER, использующей инвертированный индекс, выдает ошибку.
1
2
3
FOR doc IN viewName
  SEARCH EXISTS(doc.text, "analyzer", "text_en")
  RETURN doc

Тестирование на вложенные поля

EXISTS(path, "nested")

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

  • path (выражение пути атрибута): атрибут для проверки в документе.
  • type (строка): строковый литерал "nested".
  • ничего не возвращает: функция оценивает булево значение, но это значение не может быть возвращено. Функция может быть вызвана только в поисковом выражении. При ее использовании вне операции SEARCH или операции FILTER, использующей инвертированный индекс, выдает ошибку.

Примеры.

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

1
2
3
FOR doc IN viewName
  SEARCH EXISTS(doc.text, "nested")
  RETURN doc

Возвращает только те документы, атрибут attr и его вложенный атрибут text проиндексированы как вложенные поля:

1
2
3
FOR doc IN viewName
  SEARCH doc.attr[? FILTER EXISTS(CURRENT.text, "nested")]
  RETURN doc

Возвращает только документы из коллекции coll, чей атрибут text проиндексирован как вложенное поле инвертированным индексом:

1
2
3
FOR doc IN coll OPTIONS { indexHint: "inv-idx", forceIndexHint: true }
  FILTER EXISTS(doc.text, "nested")
  RETURN doc

Возвращает только те документы, атрибут attr и его вложенный атрибут text проиндексированы как вложенные поля:

1
2
3
FOR doc IN coll OPTIONS { indexHint: "inv-idx", forceIndexHint: true }
  FILTER doc.attr[? FILTER EXISTS(CURRENT.text, "nested")]
  RETURN doc

IN_RANGE()

IN_RANGE(path, low, high, includeLow, includeHigh) → included

Искать документы, в которых атрибут по адресу path больше (или равен) low и меньше (или равен) high.

Вы можете использовать IN_RANGE() для более эффективного поиска по сравнению с эквивалентным выражением, которое объединяет два сравнения с логической связью:

  • IN_RANGE(path, low, high, true, true) вместо low <= value AND value <= high.
  • IN_RANGE(path, low, high, true, false) вместо low <= value AND value < high
  • IN_RANGE(path, low, high, false, true) вместо low < value AND value <= high
  • IN_RANGE(path, low, high, false, false) вместо low < value AND value < high

low и high могут быть числами или строками (технически также null, true и false), но тип данных должен быть одинаковым для обоих.

Алфавитный порядок символов не учитывается ArangoSearch, т.е. запросы диапазона в операциях SEARCH над представлениями не будут следовать правилам языка в соответствии с определенной локалью анализатора (кроме анализатора collation) или языком сервера (опция запуска --default-language)! Также смотрите Известные проблемы.

Существует соответствующая функция IN_RANGE() Miscellaneous Function, которая используется вне операций SEARCH.

  • path (выражение пути атрибута): путь атрибута, который нужно проверить в документе.
  • low (число|строка): минимальное значение желаемого диапазона
  • high (число|строка): максимальное значение желаемого диапазона
  • includeLow (bool): должно ли минимальное значение быть включено в диапазон (лево-закрытый интервал) или нет (лево-открытый интервал)
  • includeHigh (bool): должно ли максимальное значение быть включено в диапазон (правый закрытый интервал) или нет (правый открытый интервал)
  • возвращает included (bool): входит ли значение в диапазон

Если low и high одинаковы, но includeLow и/или includeHigh установлены в false, то ничего не будет соответствовать. Если low больше high, то также ничего не будет соответствовать.

Пример: Использование числовых диапазонов

Чтобы найти документы с атрибутами value >= 3 и value <= 5, используя стандартный анализатор "identity", вы напишите следующий запрос:

1
2
3
FOR doc IN viewName
  SEARCH IN_RANGE(doc.value, 3, 5, true, true)
  RETURN doc.value

Это также будет соответствовать документам, которые имеют массив чисел в качестве атрибута value, где хотя бы одно из чисел находится в указанных границах.

Пример: Использование границ строк

Использование границ строк и текстового анализатора позволяет найти документы, в которых хотя бы одна лексема находится в указанном диапазоне символов:

1
2
3
FOR doc IN valView
  SEARCH ANALYZER(IN_RANGE(doc.value, "a","f", true, false), "text_en")
  RETURN doc

Это будет соответствовать {"value": "bar" } и { "value": "foo bar" }, потому что b из bar находится в диапазоне ("a" <= "b" < "f"), но не { "value": "foo" }, потому что f из foo исключено (high - "f", но includeHigh - false).

MIN_MATCH()

MIN_MATCH(expr1, ... exprN, minMatchCount) → fulfilled

Искать документы, в которых удовлетворяется хотя бы minMatchCount из заданных поисковых выражений.

Существует соответствующая функция MIN_MATCH() Miscellaneous function, которая используется вне операций SEARCH.

  • expr (выражение, повторяемое): любое допустимое поисковое выражение
  • minMatchCount (число): минимальное количество поисковых выражений, которые должны быть удовлетворены
  • возвращает fulfilled (bool): является ли хотя бы minMatchCount из указанных выражений true.

Пример: Соответствие подмножества поисковых подвыражений

Имея представление с анализатором текста, вы можете использовать его для поиска документов, в которых атрибут содержит по крайней мере две из трех лексем:

1
2
3
FOR doc IN viewName
  SEARCH ANALYZER(MIN_MATCH(doc.text == 'quick', doc.text == 'brown', doc.text == 'fox', 2), "text_en")
  RETURN doc.text

Это будет соответствовать {"text": "the quick brown fox" } и { "text": "some brown fox" }, но не { "text": "``снежная лиса`` }, который удовлетворяет только одному из условий.

MINHASH_MATCH()

MINHASH_MATCH(path, target, threshold, analyzer) → fulfilled

Сопоставляет документы с приблизительным сходством по Жаккарду не менее порога, аппроксимированным с помощью указанного анализатора minhash.

Чтобы вычислить только сигнатуры MinHash, см. функцию MINHASH() Miscellaneous function.

  • path (выражение пути атрибута|строка): путь к атрибуту в документе или строка
  • target (строка): строка для хэширования указанным анализатором и сравнения с сохраненным атрибутом.
  • порог (число, опционально): значение между 0.0 и 1.0.
  • analyzer (строка): имя анализатора minhash Analyzer.
  • возвращает fulfilled (bool): true, если приблизительное сходство по Жаккарду больше или равно указанному порогу, false в противном случае.

Пример: Поиск документов с текстом, похожим на целевой текст

Предполагая представление с анализатором minhash, вы можете использовать сохраненную сигнатуру MinHash для поиска кандидатов для более дорогого вычисления сходства по Жаккарду:

1
2
3
4
5
6
7
8
9
LET target = "the quick brown fox jumps over the lazy dog"
LET targetSingature = TOKENS(target, "myMinHash")

FOR doc IN viewName
  SEARCH MINHASH_MATCH(doc.text, target, 0.5, "myMinHash") // approximation
  LET jaccard = JACCARD(targetSingature, TOKENS(doc.text, "myMinHash"))
  FILTER jaccard > 0.75
  SORT jaccard DESC
  RETURN doc.text

NGRAM_MATCH()

Введено в: v3.7.0

NGRAM_MATCH(path, target, threshold, analyzer) → fulfilled

Искать документы, значение атрибута которых имеет n-gram similarity больше заданного порога по сравнению с целевым значением.

Сходство рассчитывается путем подсчета длины самой длинной последовательности совпадающих n-грамм, разделенной на общее количество n-грамм цели. Учитываются только полностью совпадающие n-граммы.

n-граммы для атрибута и цели создаются указанным анализатором. Увеличение длины n-граммы увеличит точность, но уменьшит допустимую погрешность. В большинстве случаев размер 2 или 3 будет хорошим выбором.

Также смотрите строковые функции NGRAM_POSITIONAL_SIMILARITY() и NGRAM_SIMILARITY() для вычисления n-граммного сходства, которое не может быть ускорено индексом вида.

  • path (выражение пути атрибута|строка): путь атрибута в документе или строка.
  • target (строка): строка для сравнения с сохраненным атрибутом.
  • threshold (число, опционально): значение между 0.0 и 1.0. По умолчанию 0.7, если не указано.
  • analyzer (строка): имя Analyzer.
  • возвращает fulfilled (bool): true, если оцененное значение сходства n-грамм больше или равно указанному порогу, false в противном случае.

{% hint 'info' %} Используйте анализатор типа ngram с preserveOriginal: false и min равным max. В противном случае оценка сходства, рассчитанная внутри анализатора, будет ниже ожидаемой.

Анализатор должен иметь включенные функции "позиция" и "частота", иначе функция NGRAM_MATCH() ничего не найдет. {% endhint %}

Пример: Использование пользовательского анализатора биграмм

Дано представление, индексирующее атрибут text, пользовательский n-граммный анализатор "bigram" (min: 2, max: 2, preserveOriginal: false, streamType: "utf8") и документ {"text": "quick red fox" }, следующий запрос будет соответствовать ему (с порогом 1.0):

1
2
3
FOR doc IN viewName
  SEARCH NGRAM_MATCH(doc.text, "quick fox", "bigram")
  RETURN doc.text

Следующие также будут соответствовать (обратите внимание на низкое пороговое значение):

1
2
3
FOR doc IN viewName
  SEARCH NGRAM_MATCH(doc.text, "quick blue fox", 0.4, "bigram")
  RETURN doc.text

Следующие не будут совпадать (обратите внимание на высокое пороговое значение):

1
2
3
FOR doc IN viewName
  SEARCH NGRAM_MATCH(doc.text, "quick blue fox", 0.9, "bigram")
  RETURN doc.text

Пример: Использование постоянных значений

NGRAM_MATCH() можно вызывать с постоянными аргументами, но для таких вызовов аргумент analyzer является обязательным (даже для вызовов внутри предложения SEARCH):

1
2
3
FOR doc IN viewName
  SEARCH NGRAM_MATCH("quick fox", "quick blue fox", 0.9, "bigram")
  RETURN doc.text
1
RETURN NGRAM_MATCH("quick fox", "quick blue fox", "bigram")

PHRASE()

PHRASE(path, phrasePart, analyzer)

PHRASE(path, phrasePart1, skipTokens1, ... phrasePartN, skipTokensN, analyzer)

PHRASE(path, [ phrasePart1, skipTokens1, ... phrasePartN, skipTokensN ], analyzer).

Поиск фразы в атрибуте ссылки. Поиск выполняется только в тех документах, в которых лексемы появляются в указанном порядке. Для поиска лексем в любом порядке используйте TOKENS().

Фраза может быть выражена в виде произвольного количества phraseParts, разделенных skipTokens количеством лексем (подстановочных знаков), либо как отдельные аргументы, либо как массив в качестве второго аргумента.

  • path (выражение пути атрибута): атрибут для проверки в документе.
  • phrasePart (строка|массив|объект): текст для поиска в токенах. Также может быть массивом, состоящим из строки, массива и объектных токенов, или токенами, чередующимися с номерами skipTokens. Указанный анализатор применяется к токенам строк и массивов, но не к токенам объектов.
  • skipTokens (число, опционально): количество лексем, которые следует рассматривать как подстановочные знаки.
  • analyzer (строка, опционально): имя Analyzer. Используется анализатор из обертывающего вызова ANALYZER(), если не указан, или по умолчанию используется "identity".
  • ничего не возвращает: функция оценивает булево значение, но это значение не может быть возвращено. Функция может быть вызвана только в поисковом выражении. Она выдает ошибку, если используется вне операции SEARCH или операции FILTER, использующей инвертированный индекс.

У выбранного анализатора должны быть включены функции position и frequency. В противном случае функция PHRASE() ничего не найдет.

Объектные лексемы

Введено в v3.7.0

  • {IN_RANGE: [low, high, includeLow, includeHigh]}: смотрите IN_RANGE(). low и high могут быть только строками.
  • {LEVENSHTEIN_MATCH: [token, maxDistance, transpositions, maxTerms, prefix]}:
    • token (строка): строка для поиска
    • maxDistance (число): максимальное расстояние Левенштейна / Дамерау-Левенштейна
    • transpositions (bool, опционально): если установлено значение false, вычисляется расстояние Левенштейна, иначе расстояние Дамерау-Левенштейна (по умолчанию)
    • maxTerms (число, опционально): учитывает только заданное число наиболее релевантных терминов. Можно передать 0, чтобы учитывать все совпадающие термины, но это может негативно сказаться на производительности. Значение по умолчанию равно 64.
    • prefix (строка, опционально): если определено, то выполняется поиск точного префикса, используя совпадения в качестве кандидатов. Затем для каждого кандидата вычисляется расстояние Левенштейна / Дамерау-Левенштейна, используя остатки строк. Эта опция может повысить производительность в случаях, когда известен общий префикс. Значение по умолчанию - пустая строка (введено в v3.7.13, v3.8.1).
  • {STARTS_WITH: [prefix]}: см. STARTS_WITH(). Массивные скобки являются необязательными
  • {TERM: [token]}: равно token, но без токенизации Анализатора. Скобки массива необязательны
  • {TERMS: [token1, ..., tokenN]}: в указанной позиции находится один из token1, ..., tokenN. Внутри массива синтаксис объекта может быть заменен на значение поля объекта, например, [..., [token1, ..., tokenN], ...].
  • {WILDCARD: [token]}: см. LIKE(). Скобки массива необязательны

Токен массива внутри массива может использоваться только в случае TERMS.

Пример: Использование текстового анализатора для поиска по фразе

Дано представление, индексирующее атрибут text с помощью анализатора "text_en" и документ {"text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit" }, следующий запрос будет соответствовать ему:

1
2
3
FOR doc IN viewName
  SEARCH PHRASE(doc.text, "lorem ipsum", "text_en")
  RETURN doc.text

Однако это поисковое выражение не работает, потому что лексемы "ipsum" и "lorem" не появляются в этом порядке:

1
PHRASE(doc.text, "ipsum lorem", "text_en")

Пример: Пропуск лексем для поиска по близости

Чтобы найти соответствие между "ipsum" и "amet" с любыми двумя лексемами между ними, вы можете использовать следующее поисковое выражение:

1
PHRASE(doc.text, "ipsum", 2, "amet", "text_en")

Значение skipTokens, равное 2, определяет, сколько лексем подстановочного знака должно находиться между ipsum и amet. Значение skipTokens, равное 0, означает, что лексемы должны быть соседними. Отрицательные значения допустимы, но не очень полезны. Эти три поисковых выражения эквивалентны:

1
2
3
PHRASE(doc.text, "lorem ipsum", "text_en")
PHRASE(doc.text, "lorem", 0, "ipsum", "text_en")
PHRASE(doc.text, "ipsum", -1, "lorem", "text_en")

Пример: Использование PHRASE() с массивом лексем

Функция PHRASE() также принимает в качестве второго аргумента массив с параметрами phrasePart и skipTokens в качестве элементов.

1
2
FOR doc IN myView SEARCH PHRASE(doc.title, ["quick brown fox"], "text_en") RETURN doc
FOR doc IN myView SEARCH PHRASE(doc.title, ["quick", "brown", "fox"], "text_en") RETURN doc

Эта вариация синтаксиса позволяет использовать вычисляемые выражения:

1
2
3
4
LET proximityCondition = [ "foo", ROUND(RAND()*10), "bar" ]
FOR doc IN viewName
  SEARCH PHRASE(doc.text, proximityCondition, "text_en")
  RETURN doc
1
2
LET tokens = TOKENS("quick brown fox", "text_en") // ["quick", "brown", "fox"]
FOR doc IN myView SEARCH PHRASE(doc.title, tokens, "text_en") RETURN doc

Приведенный выше пример эквивалентен более громоздкой и статичной форме:

1
FOR doc IN myView SEARCH PHRASE(doc.title, "quick", 0, "brown", 0, "fox", "text_en") RETURN doc

Вы можете опционально указать количество skipTokens в форме массива перед каждым элементом строки:

1
FOR doc IN myView SEARCH PHRASE(doc.title, ["quick", 1, "fox", "jumps"], "text_en") RETURN doc

Это то же самое, что и следующее:

1
FOR doc IN myView SEARCH PHRASE(doc.title, "quick", 1, "fox", 0, "jumps", "text_en") RETURN doc

Пример: Обработка массивов без членов

Пустые массивы пропускаются:

1
FOR doc IN myView SEARCH PHRASE(doc.title, "quick", 1, [], 1, "jumps", "text_en") RETURN doc

Этот запрос эквивалентен:

1
FOR doc IN myView SEARCH PHRASE(doc.title, "quick", 2 "jumps", "text_en") RETURN doc

Предоставление только пустых массивов допустимо, но не даст никаких результатов.

Пример: Использование объектных маркеров

Использование объектных маркеров STARTS_WITH, WILDCARD, LEVENSHTEIN_MATCH, TERMS и IN_RANGE:

1
2
3
4
5
6
7
FOR doc IN myView SEARCH PHRASE(doc.title,
  {STARTS_WITH: ["qui"]}, 0,
  {WILDCARD: ["b%o_n"]}, 0,
  {LEVENSHTEIN_MATCH: ["foks", 2]}, 0,
  {TERMS: ["jump", "run"]}, 0, // Analyzer not applied!
  {IN_RANGE: ["over", "through", true, false]},
  "text_en") RETURN doc

Обратите внимание, что в анализаторе text_en включена функция stemming, но для объектных лексем она не применяется. {TERMS: ["jumps", "runs"]} не будет соответствовать индексированному (и стебельчатому!) значению атрибута. Поэтому в данном примере из обоих слов вручную удаляется концевое s, которое должно быть удалено.

Приведенный выше пример эквивалентен следующему:

1
2
3
4
5
6
7
8
FOR doc IN myView SEARCH PHRASE(doc.title,
[
  {STARTS_WITH: "qui"}, 0,
  {WILDCARD: "b%o_n"}, 0,
  {LEVENSHTEIN_MATCH: ["foks", 2]}, 0,
  ["jumps", "runs"], 0, // Analyzer is applied using this syntax
  {IN_RANGE: ["over", "through", true, false]}
], "text_en") RETURN doc

STARTS_WITH()

STARTS_WITH(path, prefix) → startsWith

Искать значение атрибута, которое начинается с prefix. Если атрибут обрабатывается токенизирующим анализатором (тип "текст" или "разделитель") или если это массив, то для соответствия документу достаточно одной лексемы/элемента, начинающегося с префикса.

Алфавитный порядок символов не учитывается ArangoSearch, т.е. запросы диапазона в операциях SEARCH против Views не будут следовать правилам языка согласно определенной локали анализатора (кроме анализатора collation) или языку сервера (опция запуска --default-language)! Также смотрите Известные проблемы.

Существует соответствующая функция STARTS_WITH() String function, которая используется вне операций SEARCH.

  • path (выражение пути атрибута): путь атрибута, с которым нужно сравнить в документе.
  • префикс (строка): строка для поиска в начале текста.
  • возвращает startsWith (bool): начинается ли указанный атрибут с заданного префикса.

STARTS_WITH(path, prefixes, minMatchCount) → startsWith

Введено в: v3.7.1

Искать значение атрибута, которое начинается с одного из префиксов, или, опционально, хотя бы с minMatchCount префиксов.

  • path (выражение пути к атрибуту): путь к атрибуту, с которым нужно сравнить в документе.
  • prefixes (массив): массив строк для поиска в начале текста
  • minMatchCount (число, опционально): минимальное количество префиксов для поиска, которое должно быть удовлетворено. По умолчанию 1.
  • возвращает startsWith (bool): начинается ли указанный атрибут хотя бы с minMatchCount из заданных префиксов.

Пример: Поиск префикса точного значения

Для соответствия документу {"text": "lorem ipsum..." } с помощью префикса и анализатора "identity" вы можете использовать его следующим образом:

1
2
3
FOR doc IN viewName
  SEARCH STARTS_WITH(doc.text, "lorem ip")
  RETURN doc

Пример: Поиск префикса в тексте

Этот запрос будет соответствовать { "text": "lorem ipsum" }, а также { "text": ["lorem", "ipsum" ] }, заданный представлением, которое индексирует атрибут text и обрабатывает его с помощью анализатора "text_en":

1
2
3
FOR doc IN viewName
  SEARCH ANALYZER(STARTS_WITH(doc.text, "ips"), "text_en")
  RETURN doc.text

Обратите внимание, что он не будет соответствовать {"text": "IPS (коммутация в плоскости)" } без модификации запроса. Префиксы были переданы в STARTS_WITH() как есть, но встроенный анализатор text_en, используемый для индексирования, имеет включенное стеблирование. Таким образом, индексированные значения выглядят следующим образом:

1
RETURN TOKENS("IPS (in-plane switching)", "text_en")
1
[["ip", "in", "plane", "switch"]]

Из ips удаляется s, что приводит к тому, что префикс ips не совпадает с индексированной лексемой ip. Чтобы избежать этой проблемы, можно либо создать пользовательский анализатор текста с отключенным стеблированием, либо применить стеблирование к префиксам:

1
2
3
FOR doc IN viewName
  SEARCH ANALYZER(STARTS_WITH(doc.text, TOKENS("ips", "text_en")), "text_en")
  RETURN doc.text

Пример: Поиск одного или нескольких префиксов

Функция STARTS_WITH() принимает массив альтернативных префиксов, из которых только один должен совпадать:

1
2
3
FOR doc IN viewName
  SEARCH ANALYZER(STARTS_WITH(doc.text, ["something", "ips"]), "text_en")
  RETURN doc.text

Он будет соответствовать документу { "text": "lorem ipsum" }, но и {"text": "это что-то" }, поскольку хотя бы одно из слов начинается с заданного префикса.

Снова тот же запрос, но с явным значением minMatchCount:

1
2
3
FOR doc IN viewName
  SEARCH ANALYZER(STARTS_WITH(doc.text, ["wrong", "ips"], 1), "text_en")
  RETURN doc.text

Число может быть увеличено, чтобы требовать наличия по крайней мере такого количества префиксов:

1
2
3
FOR doc IN viewName
  SEARCH ANALYZER(STARTS_WITH(doc.text, ["lo", "ips", "something"], 2), "text_en")
  RETURN doc.text

Это все равно будет соответствовать {"text": "lorem ipsum" }, потому что найдены по крайней мере два префикса (lo и ips), но не {"text": "that is something" }, который содержит только один из префиксов (something).

LEVENSHTEIN_MATCH()

Введено в: v3.7.0

LEVENSHTEIN_MATCH(path, target, distance, transpositions, maxTerms, prefix) → fulfilled

Искать документы с расстоянием Damerau-Levenshtein distance меньшим или равным distance между сохраненным значением атрибута и target. В качестве опции он может сопоставлять документы, используя чистое расстояние Левенштейна.

Смотрите LEVENSHTEIN_DISTANCE(), если вы хотите вычислить расстояние редактирования двух строк.

  • path (выражение пути атрибута|строка): путь атрибута, с которым нужно сравнить в документе, или строка.
  • target (строка): строка для сравнения с сохраненным атрибутом.
  • distance (число): максимальное расстояние редактирования, которое может быть между 0 и 4, если transpositions - false, и между 0 и 3, если true.
  • transpositions (bool, опционально): если установлено значение false, вычисляется расстояние Левенштейна, иначе расстояние Дамерау-Левенштейна (по умолчанию)
  • maxTerms (число, опционально): учитывает только заданное число наиболее релевантных терминов. Можно передать 0, чтобы учитывать все совпадающие термины, но это может негативно сказаться на производительности. Значение по умолчанию равно 64.
  • returns fulfilled (bool): true, если вычисленное расстояние меньше или равно distance, false в противном случае.
  • префикс (строка, опционально): если определен, то выполняется поиск точного префикса, используя совпадения в качестве кандидатов. Затем для каждого кандидата вычисляется расстояние Левенштейна / Дамерау-Левенштейна, используя значение target и остатки строк, что означает, что префикс должен быть удален из target. Эта опция может улучшить производительность в случаях, когда известен общий префикс. Значение по умолчанию - пустая строка (введено в v3.7.13, v3.8.1).

Пример: Сопоставление с транспозициями и без них

Расстояние Левенштейна между quick и quikc равно 2, потому что для перехода от одного к другому требуется две операции (удалить k, вставить k в другую позицию).

1
2
3
FOR doc IN viewName
  SEARCH LEVENSHTEIN_MATCH(doc.text, "quikc", 2, false) // matches "quick"
  RETURN doc.text

Расстояние Дамерау-Левенштейна равно 1 (переместите k в конец).

1
2
3
FOR doc IN viewName
  SEARCH LEVENSHTEIN_MATCH(doc.text, "quikc", 1) // matches "quick"
  RETURN doc.text

Пример: Сопоставление с префиксным поиском

Сопоставьте документы с расстоянием Левенштейна, равным 1, с префиксом qui. Расстояние редактирования вычисляется с помощью поискового термина kc (quikc с удаленным префиксом qui) и сохраненного значения без префикса (например, ck). Префикс qui является постоянным.

1
2
3
FOR doc IN viewName
  SEARCH LEVENSHTEIN_MATCH(doc.text, "kc", 1, false, 64, "qui") // matches "quick"
  RETURN doc.text

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

1
2
3
4
5
6
7
LET input = "quikc"
LET prefixSize = 3
LET prefix = LEFT(input, prefixSize)
LET suffix = SUBSTRING(input, prefixSize)
FOR doc IN viewName
  SEARCH LEVENSHTEIN_MATCH(doc.text, suffix, 1, false, 64, prefix) // matches "quick"
  RETURN doc.text

Пример: Выбор расстояния редактирования на основе длины строки

Вы можете захотеть выбрать максимальное расстояние редактирования в зависимости от длины строки. Если хранимым атрибутом является строка quick, а целевой строкой - quicksands, то расстояние Левенштейна равно 5, при этом 50% символов не совпадают. Если входными данными являются q и qu, то расстояние составляет всего 1, хотя и здесь несовпадение составляет 50%.

1
2
3
4
5
6
LET target = "input"
LET targetLength = LENGTH(target)
LET maxDistance = (targetLength > 5 ? 2 : (targetLength >= 3 ? 1 : 0))
FOR doc IN viewName
  SEARCH LEVENSHTEIN_MATCH(doc.text, target, maxDistance, true)
  RETURN doc.text

LIKE()

Введено в: v3.7.2

LIKE(path, search) → bool

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

  • _: Один произвольный символ
  • %: Ноль, один или много произвольных символов
  • \_: Буквальное подчеркивание
  • \%: Буквальный знак процента

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

  • \ в переменных привязки (режим просмотра Таблица) в веб-интерфейсе (автоматически экранируется в \, если значение не заключено в двойные кавычки и уже экранировано должным образом)
  • \ в переменных привязки (режим представления JSON) и запросах в веб-интерфейсе
  • \\ в переменных привязки в arangosh
  • \\\\ в запросах в arangosh
  • Вдвое больше по сравнению с arangosh в оболочках, использующих обратные слеши для экранирования (\\\ в переменных привязки и \\\\ в запросах)

Поиск с помощью функции LIKE() в контексте операции SEARCH поддерживается индексами View. Функция String LIKE() используется в других контекстах, например, в операциях FILTER, и не может быть ускорена каким-либо индексом с другой стороны. Еще одно отличие заключается в том, что вариант ArangoSearch не принимает третий аргумент для включения нечувствительного к регистру соответствия. Этим можно управлять с помощью анализаторов.

  • path (выражение пути к атрибуту): путь к атрибуту, с которым нужно сравнить в документе.
  • search (строка): шаблон поиска, который может содержать символы подстановки % (означает любую последовательность символов, включая ни одного) и _ (любой отдельный символ). Буквальные % и _ должны быть экранированы обратными слешами.
  • возвращает bool (bool): true, если шаблон содержится в text, и false в противном случае.

Пример: Поиск с использованием символов подстановки

1
2
3
FOR doc IN viewName
  SEARCH ANALYZER(LIKE(doc.text, "foo%b_r"), "text_en")
  RETURN doc.text

LIKE также может использоваться в форме оператора:

1
2
3
FOR doc IN viewName
  SEARCH ANALYZER(doc.text LIKE "foo%b_r", "text_en")
  RETURN doc.text

Гео-функции

Следующие функции могут быть ускорены с помощью индексов View. Существуют соответствующие Geo Functions для обычного типа геоиндексов, а также функции общего назначения, такие как конструкторы GeoJSON, которые можно использовать в сочетании с ArangoSearch.

GEO_CONTAINS()

Введена в: v3.8.0

GEO_CONTAINS(geoJsonA, geoJsonB) → bool

Проверяет, содержит ли объект GeoJSON geoJsonA полностью geoJsonB (каждая точка в B также находится в A).

  • geoJsonA (объект|массив): первый объект GeoJSON или массив координат (в порядке долготы, широты)
  • geoJsonB (объект|массив): второй объект GeoJSON или массив координат (в порядке долготы, широты).
  • возвращает bool (bool): true, если каждая точка в B также содержится в A, false в противном случае.

GEO_DISTANCE()

Введено в: v3.8.0

GEO_DISTANCE(geoJsonA, geoJsonB) → distance

Возвращает расстояние между двумя GeoJSON объектами, измеренное от центроида каждой фигуры.

  • geoJsonA (object|array): первый объект GeoJSON или массив координат (в порядке долготы, широты).
  • geoJsonB (объект|массив): второй объект GeoJSON или массив координат (в порядке долготы, широты).
  • возвращает расстояние (число): расстояние между точками центроида двух объектов на опорном эллипсоиде

GEO_IN_RANGE()

Введено в: v3.8.0

GEO_IN_RANGE(geoJsonA, geoJsonB, low, high, includeLow, includeHigh) → bool

Проверяет, лежит ли расстояние между двумя GeoJSON объектами в заданном интервале. Расстояние измеряется от центроида каждой фигуры.

  • geoJsonA (object|array): первый объект GeoJSON или массив координат (в порядке долготы, широты).
  • geoJsonB (объект|массив): второй объект GeoJSON или массив координат (в порядке долготы, широты).
  • low (число): минимальное значение желаемого диапазона
  • high (число): максимальное значение желаемого диапазона
  • includeLow (bool, необязательный): должно ли минимальное значение быть включено в диапазон (лево-закрытый интервал) или нет (лево-открытый интервал). Значение по умолчанию - true
  • includeHigh (bool): включать ли максимальное значение в диапазон (интервал справа-закрытый) или нет (интервал справа-открытый). Значение по умолчанию - true.
  • возвращает bool (bool): лежит ли оцениваемое расстояние в диапазоне

GEO_INTERSECTS()

Введено в: v3.8.0

GEO_INTERSECTS(geoJsonA, geoJsonB) → bool

Проверяет, пересекается ли GeoJSON объект geoJsonA с geoJsonB (т.е. хотя бы одна точка B находится в A или наоборот).

  • geoJsonA (object|array): первый объект GeoJSON или массив координат (в порядке долготы, широты).
  • geoJsonB (object|array): второй объект GeoJSON или массив координат (в порядке долготы, широты).
  • возвращает bool (bool): true, если A и B пересекаются, false в противном случае.

Функции оценки

Скоринговые функции возвращают значение рейтинга для документов, найденных операцией SEARCH. Чем лучше документы соответствуют поисковому выражению, тем выше возвращаемое число.

Первым аргументом любой скоринговой функции всегда является документ, выданный операцией FOR над представлением arangosearch.

Чтобы отсортировать набор результатов по релевантности, причем более релевантные документы идут первыми, отсортируйте их в порядке по убыванию по баллу (например, SORT BM25(...) DESC).

Вы можете рассчитать пользовательские оценки на основе функции оценки, используя атрибуты документа и числовые функции (например, TFIDF(doc) * LOG(doc.value)):

1
2
3
4
FOR movie IN imdbView
  SEARCH PHRASE(movie.title, "Star Wars", "text_en")
  SORT BM25(movie) * LOG(movie.runtime + 1) DESC
  RETURN movie

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

1
2
3
4
5
FOR a IN viewA
  FOR c IN coll
    FOR b IN viewB
      SORT TFIDF(b), c.name, BM25(a)
      ...

BM25()

BM25(doc, k, b) → score

Сортирует документы, используя алгоритм Best Matching 25 (Okapi BM25).

  • doc (документ): должен быть испущен FOR ... IN viewName
  • k (число, опционально): калибрует масштабирование частоты текстовых терминов. По умолчанию 1.2. Значение k, равное 0, соответствует бинарной модели (без частоты терминов), а большое значение соответствует использованию необработанной частоты терминов.
  • b (число, опционально): определяет масштабирование по общей длине текста. По умолчанию 0.75. При крайних значениях коэффициента b, BM25 превращается в функции ранжирования, известные как:
    • BM11 для b = 1 (соответствует полному масштабированию веса термина по общей длине текста)
    • BM15 для b = 0 (соответствует отсутствию нормализации длины)
  • возвращает score (число): вычисленное значение ранжирования

{% hint 'info' %} Анализаторы, используемые для индексирования атрибутов документа, должны иметь включенную функцию частота. В противном случае функция BM25() вернет значение 0. Анализаторы также должны иметь включенную функцию "norm", иначе нормализация будет отключена, что не имеет смысла для BM25 и BM11. BM15 не нуждается в функции "norm", так как в нем нет нормализации длины. {% endhint %}

Пример: Сортировка по умолчанию по показателю BM25()

Сортировка по релевантности с помощью BM25 при настройках по умолчанию:

1
2
3
4
FOR doc IN viewName
  SEARCH ...
  SORT BM25(doc) DESC
  RETURN doc

Пример: Сортировка с настроенным ранжированием BM25()

Сортировка по релевантности, с удвоенной взвешенной частотой терминов и с нормализацией длины полного текста:

1
2
3
4
FOR doc IN viewName
  SEARCH ...
  SORT BM25(doc, 2.4, 1) DESC
  RETURN doc

TFIDF()

TFIDF(doc, normalize) → score.

Сортирует документы, используя алгоритм терминальная частота-инверсная частота документа (TF-IDF).

  • doc (документ): должен выдаваться FOR ... IN viewName
  • normalize (bool, опционально): указывает, должны ли баллы быть нормализованы. По умолчанию false.
  • возвращает score (число): вычисленное значение рейтинга.

Анализаторы, используемые для индексирования атрибутов документа, должны иметь включенную функцию частота. В противном случае функция TFIDF() вернет значение 0. Анализаторы должны иметь включенную функцию "norm", если вы хотите использовать TFIDF() с параметром normalize, установленным в true.

Пример: Сортировка по умолчанию по TFIDF() показателю

Сортировка по релевантности с использованием показателя TF-IDF:

1
2
3
4
FOR doc IN viewName
  SEARCH ...
  SORT TFIDF(doc) DESC
  RETURN doc

Пример: Сортировка по показателю TFIDF() с нормализацией

Сортировка по релевантности с использованием нормализованного показателя TF-IDF:

1
2
3
4
FOR doc IN viewName
  SEARCH ...
  SORT TFIDF(doc, true) DESC
  RETURN doc

Пример: Сортировка по значению и TFIDF()

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

1
2
3
4
FOR doc IN viewName
  SEARCH ...
  SORT doc.text, TFIDF(doc) DESC
  RETURN doc

Функции выделения поиска

Выделение поиска доступно только в версии Enterprise Edition, включая платформу ArangoGraph Insights Platform.

OFFSET_INFO()

OFFSET_INFO(doc, paths) → offsetInfo

Возвращает пути атрибутов и смещения подстрок совпавших терминов, фраз или n-грамм для целей выделения поиска.

  • doc (документ): должен быть выдан FOR ... IN viewName

  • paths (строка|массив): строка или массив строк, каждая из которых описывает путь атрибута и элемента массива, для которых вы хотите получить смещения. Используйте . для доступа к вложенным объектам и [n] с n - индексом массива для указания элементов массива. Атрибуты должны быть проиндексированы анализаторами с включенной функцией offset.

  • возвращает offsetInfo (массив): массив объектов, ограниченный по умолчанию 10 смещениями на путь. Каждый объект имеет следующие атрибуты:

    • имя (массив): атрибут и путь элемента массива в виде массива строк и чисел. Вы можете передать это имя функции VALUE() для динамического поиска значения.

    • offsets (массив): массив массивов с совпадающими позициями. Каждый внутренний массив имеет два элемента с начальным смещением и длиной совпадения.

Смещение описывает позиции в байтах, а не в символах. Может потребоваться учет символов, закодированных с использованием нескольких байтов.


OFFSET_INFO(doc, rules) → offsetInfo

  • doc (документ): должен быть выдан FOR ... IN viewName
  • rules (массив): массив объектов со следующими атрибутами:
    • name (строка): атрибут и путь элемента массива, для которого вы хотите получить смещения. Используйте . для доступа к вложенным объектам и [n] с n - индексом массива для указания элементов массива. Атрибуты должны быть проиндексированы анализаторами с включенной функцией offset.
    • options (объект): объект со следующими атрибутами:
      • maxOffsets (число, опционально): общее количество смещений для сбора по каждому пути. По умолчанию: 10.
      • limits (объект, опционально): объект со следующими атрибутами:
        • term (число, опционально): общее количество смещений терминов, которые необходимо собрать для каждого пути. По умолчанию: 232.
        • phrase (число, опционально): общее количество смещений фраз для сбора по каждому пути. По умолчанию: 232.
        • ngram (число, опционально): общее количество n-грамм, которые нужно собрать для каждого пути. По умолчанию: 232.
  • возвращает offsetInfo (массив): массив объектов, каждый из которых имеет следующие атрибуты:
    • имя (массив): атрибут и путь элемента массива в виде массива строк и чисел. Вы можете передать это имя в VALUE() для динамического поиска значения.
    • offsets (массив): массив массивов с совпадающими позициями, урезанными до заданных пределов. Каждый внутренний массив имеет два элемента с начальным смещением и длиной совпадения.

Начальное смещение и длина описывают позиции в байтах, а не в символах. Может потребоваться учет символов, закодированных с использованием нескольких байтов.

Примеры

Поиск в представлении и получение информации о смещении для совпадений:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@startDocuBlockInline aqlOffsetInfo
@EXAMPLE_ARANGOSH_OUTPUT{aqlOffsetInfo}
~ db._create("food");
~ db.food.save({ name: "avocado", description: { en: "Авокадо - это вечнозеленое дерево среднего размера, родом из Америки". } });
~ db.food.save({ name: "tomato", description: { en: "Помидор - это съедобная ягода растения томата". } });
~ var analyzers = require("@arangodb/analyzers");
~ var analyzer = analyzers.save("text_en_offset", "text", { locale: "en", stopwords: [] }, ["frequency", "norm", "position", "offset"]);
~ db._createView("food_view", "arangosearch", { links: { food: { fields: { описание: { fields: { en: { analyzers: ["text_en_offset"] } } } } } } });
~ assert(db._query(`FOR d IN food_view COLLECT WITH COUNT INTO c RETURN c`).toArray()[0] === 2);
| db._query(`FOR doc IN food_view
| SEARCH ANALYZER(TOKENS("авокадо-помидор", "text_en_offset") ANY == doc.description.en, "text_en_offset")
    RETURN OFFSET_INFO(doc, ["description.en"])`);
~ db._dropView("food_view");
~ db._drop("food");
~ analyzers.remove(analyzer.name);
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock aqlOffsetInfo

Полные примеры смотрите в Выделение поиска.

Комментарии