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

FOR

Универсальное ключевое слово FOR можно использовать для перебора коллекции или представления, всех элементов массива или для обхода графа.

Синтаксис

Общий синтаксис для перебора коллекций и массивов:

FOR variableName IN expression

Существует также специальный вариант для обхода графа:

FOR vertexVariableName [, edgeVariableName [, pathVariableName ] ]
  IN traversalExpression

Для представлений есть специальное (необязательное) ключевое слово SEARCH:

FOR variableName IN viewName SEARCH searchExpression

Представления нельзя использовать в качестве коллекций ребер в обходах:

1
FOR v IN 1..3 ANY startVertex viewName /* неверно! */

Все варианты могут дополнительно заканчиваться предложением OPTIONS { … }.

Применение

Каждый элемент массива, возвращаемый выражением, посещается ровно один раз. Требуется, чтобы выражение возвращало массив во всех случаях. Пустой массив также разрешен. Текущий элемент массива становится доступным для дальнейшей обработки в переменной, указанной в variableName.

1
2
FOR u IN users
  RETURN u

Это будет перебирать все элементы из массива users (обратите внимание: этот массив состоит из всех документов из коллекции с именем users в данном случае) и сделает текущий элемент массива доступным в переменной u. u не изменяется в этом примере, а просто вставляется в результат с помощью ключевого слова RETURN.

При переборе массивов на основе коллекций, как показано здесь, порядок документов не определен, если явный порядок сортировки не определен с помощью инструкции SORT.

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

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

1
2
3
4
5
FOR year IN [ 2011, 2012, 2013 ]
  RETURN {
    "year" : year,
    "isLeapYear" : year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
  }

Допускается также вложение нескольких операторов FOR. Когда операторы FOR являются вложенными, будет создано перекрестное произведение элементов массива, возвращаемых отдельными операторами FOR.

1
2
3
FOR u IN users
  FOR l IN locations
    RETURN { "user" : u, "location" : l }

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

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

1
2
3
FOR u IN users
  LET subquery = (FOR l IN locations RETURN l.location)
  RETURN { "user": u, "locations": subquery }

Также см. Объединение запросов с подзапросами.

Параметры

Для коллекций и представлений конструкция FOR поддерживает необязательное предложение OPTIONS для изменения поведения. Общий синтаксис:

FOR variableName IN expression OPTIONS { option: value, ... }

indexHint

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

1
FOR … IN … OPTIONS { indexHint: "byName" }
1
FOR … IN … OPTIONS { indexHint: ["byName", "byColor"] }

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

Если ни один из указанных индексов не подходит, он возвращается к своей обычной логике выбора другого индекса или терпит неудачу, если включен forceIndexHint.

forceIndexHint

Подсказки индекса не применяются по умолчанию. Если для forceIndexHint задано значение true, то генерируется ошибка, если indexHint не содержит пригодный для использования индекс, вместо использования резервного индекса или вообще без использования индекса.

1
FOR … IN … OPTIONS { indexHint: … , forceIndexHint: true }

disableIndex

Добавлено в: v3.9.1

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

Рассмотрим следующий запрос и индекс на присутствие атрибута value:

1
2
3
FOR doc IN collection
  FILTER doc.value <= 99
  RETURN doc.other

В этом случае оптимизатор, скорее всего, выберет индекс на value, потому что он будет удовлетворять условию FILTER запроса. Чтобы вернуть значение атрибута other, запрос должен дополнительно просмотреть документы для каждого значения индекса, которое удовлетворяет условию FILTER. Если количество записей индекса велико (близко или равно количеству документов в коллекции), то использование индекса может вызвать больше работы, чем простое сканирование всех документов в коллекции.

Оптимизатор, скорее всего, предпочтет сканирование индекса полному сканированию коллекции, даже если сканирование индекса в итоге окажется медленнее. Вы можете заставить оптимизатора не использовать индекс для любого цикла FOR, используя подсказку disableIndex и установив ее в значение true:

1
2
3
FOR doc IN collection OPTIONS { disableIndex: true }
  FILTER doc.value <= 99
  RETURN doc.other

Использование disableIndex: false не влияет на геоиндексы или полнотекстовые индексы.

Обратите внимание, что установка disableIndex: true плюс indexHint является неоднозначной. В этом случае оптимизатор всегда предпочтет подсказку disableIndex.

maxProjections

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

По умолчанию, оптимизатор запросов будет рассматривать не более 5 атрибутов документа на цикл FOR для использования в качестве проекций. Если в цикле FOR обращается более 5 атрибутов коллекции, оптимизатор предпочтет извлечь полный документ и не использовать проекции.

Пороговое значение в 5 атрибутов является произвольным и может быть изменено с помощью подсказки maxProjections. Значение по умолчанию для maxProjections равно 5, что совместимо с ранее жестко заданным значением по умолчанию.

Например, при использовании подсказки maxProjections, равной 7, следующий запрос извлечет 7 атрибутов в качестве проекций из исходного документа:

1
2
FOR doc IN collection OPTIONS { maxProjections: 7 }
  RETURN [ doc.val1, doc.val2, doc.val3, doc.val4, doc.val5, doc.val6, doc.val7 ]

Обычно нет необходимости корректировать значение maxProjections, но есть несколько угловых случаев, когда это может иметь смысл:

  • Может быть полезно увеличить maxProjections при извлечении множества мелких атрибутов из очень больших документов, при этом следует избегать полного копирования документов.
  • Может быть выгодно уменьшить maxProjections, чтобы избежать использования проекций, если стоимость проекций выше, чем создание копий полных документов. Это может быть актуально для очень маленьких документов.

Начиная с версии 3.10, maxProjections можно использовать в Graph Traversals (только в Enterprise Edition).

useCache

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

Вы можете отключить кэширование в памяти, которое было включено для постоянных индексов в каждом конкретном случае. Это полезно для запросов, которые обращаются к индексам с включенным кэшем в памяти, но для которых известно, что использование кэша будет иметь негативное влияние на производительность. В этом случае можно установить подсказку useCache на false:

1
2
3
FOR doc IN collection OPTIONS { useCache: false }
  FILTER doc.value == @value
  ...

Вы можете установить подсказку отдельно для каждого цикла FOR. Если вы не зададите подсказку useCache, она неявно будет иметь значение по умолчанию true.

Подсказка не влияет на циклы FOR, которые не используют индексы, или на циклы FOR, которые обращаются к индексам, не имеющим включенного кэша в памяти. Он также не влияет на запросы, для которых существующий кэш в памяти не может быть использован (т.е. потому что условие фильтрации запроса не содержит поиска равенства для всех атрибутов индекса). Его нельзя использовать для операций FOR, которые выполняют итерации над представлениями или обход графов.

Также смотрите Кэширование значений индексов.

lookahead

Тип многомерного индекса zkd поддерживает необязательную подсказку индекса для настройки производительности:

1
FOR … IN … OPTIONS { lookahead: 32 }

См. Многомерные индексы.

Комментарии