ArangoDB – мультимодельная БД с возможностью хранения данных как графов, документов и ключ-значение.

Взял материал с бесплатного курса на udemy и Outline курса 
Стоит обратить внимание на training center и доки

Можно работать по HTTP API, фронттерминал и библиотеку питона

Концепция

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

Есть два типа коллекций:

  • Стандартная. Хранилище документов json, специальные поля _key, _rev, _idkey можно задать самому. Последние два создаются автоматически.

    • _key – ключ объекта в коллекции. ВАЖНО: case sensitive

    • _rev – используется для внутренних алгоритмов

    • _id – используется для связи с другими коллекциями. Имеет формат {collection name}/_key

  • Edge. Специальные коллекции, хранящие в себе объекты связи между объектами стандартных коллекций. Имею два дополнительных поля _to, _from, в которых хранятся _id объектов, которых edge объект связывает

Есть фронт для работы с БД.
Есть утилита для подключения и работы с БД в терминале.

CRUD

Используется свой язык AQL

Создание

Создание объектов. Добавляем какие хотим значения, при попытке добавления объекта с существующем _key будет ошибка.

Синтаксис: 

INSERT {key: value} INTO collection [RETURN NEW]

RETURN NEW позволяет вернуть добавленный объект

Чтение

Чтение объектов
Синтаксис:

RETURN DOCUMENT(_id) – вернёт объект по _id 
RETURN DOCUMENT(collection_name, [_key, ...]) – вернёт список объектов из коллекции по ключам

Обновление

Обновление объектов

Синтаксис: 

UPDATE {_key: "value"} WITH {newVal: 1234} IN collection

Удаление

Синтаксис: 

REMOVE {_key: "value"} IN collection

FOR

Синтаксис: FOR variableName IN expression

  • Итерируется по массиву объектов

  • Поддерживает вложенность

  • Особенности в работе с графами

Update нескольких документов:

FOR doc in ["key1", "key2"]:
  UPDATE doc WITH {newVal: 1234} IN collection

Фичи

Индексы

Можем ускорить операции индексируя ключи объектов. По дефолту ключи _key, _id, _to и _from индексируются.

Есть 7 типов индексов:

  • Primary – автоматически генерируемый для покрытия _key и _id

  • Edge – автоматически генерируемый для покрытия _from и _to

  • Hash – создаётся вручную и покрывает нужные поля

  • Skiplist

  • Persistent

  • Geo

  • Fulltext

При создании индекса запускается процесс индексации и рассчитывается коэффициент Selectivity, который отвечает за приоритет при выборе индекса для работы запроса

Фильтрация

Синтаксис: FILTER condition

В одном запросе может быть несколько фильтров.
Например, хотим получить вип полёты:

FOR flight IN flights 
  FILTER flight.type == "VIP" 
  RETURN flight

Без индексации на большом объеме данных может выполнятся сотни миллисекунд.

Объединение

Работают за счёт вложенных циклов. 
Например, хотим получить все полёты В аэропорты Далласа.

FOR airport IN airports
  FILTER airport.city == "Dallas"
    FOR flight in flights 
      FILTER flight._to == airport._id
      RETURN {"airport": airport.name, "flight": flight.FlightNum}

Группировка

Синтаксис:

COLLECT variableName = expression options

Например, хотим собрать все штаты аэропортов:

FOR airport IN airports COLLECT state = airport.state RETURN state

Или посчитать сколько аэропортов в каждом штате и отсортировать по убыванию

FOR airport IN airports
  COLLECT state = airport.state WITH COUNT INTO total
  SORT total DESC
    RETURN {"state": state, "total":total}

Графы

Связь объектов коллекций происходит с помощью коллекций связи (edge collections). В стандартных коллекциях у каждого объекта есть поле _id, которое содержит информацию о коллекции объекта и ключу объекта в этой коллекции.
Объекты коллекции edge имеют поля _to и _from, которые содержат _id объектов, которые они связывают. Объекты этой коллекции также json, то есть мы можем добавлять в них любую информацию, описывая связь между объектами.

Синтаксис:

FOR vertex, edge, path IN 1..1 OUTBOUND _id GRAPH edge_collection RETURN path
FOR vertex, edge, path IN 1..1 OUTBOUND _id edge_collection RETURN path – анонимный граф, потому что не указали GRAPH. Можем использовать несколько edge коллекций

vertex – текущая вершина, обязательна
edge – текущее ребро
path – содержит два списка: всех вершин и всех рёбер между запрошенными вершинами

IN задаёт глубину поиска, min..max
OUTBOUND/INBOUND/ANY задаёт движение поиск. Смотрит на ключи _from, _to соответсвенно.
_id содержит строку с id объекта. Может быть самим объектом
GRAPH указывает на коллекцию edge типа, по которой будем искать связи

Например, мы хотим прямой рейс из Сан-Франциско на Гавайи:

FOR airport in airports
  FILTER airport.city == "San Francisco"
    FOR v, e, p IN 1..1 OUTBOUND airport flights
    FILTER v._id == "airports/KOA"
    RETURN p

Или хотим рейс с пересадками из Сан-Франциско на Гавайи:

FOR airport in airports
  FILTER airport.city == "San Francisco"
    FOR v, e, p IN 2..3 OUTBOUND airport flights
    FILTER v._id == "airports/KOA"
    RETURN p

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

Поиск

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

ArangoSearch состоит из двух компонентов: движок поиска и движок интеграций.

Движок поиска – это analyzers, views и links
Analyzers позволяют сконфигурировать правила, по которым текст будет обработан. Есть набор встроенных анализаторов на популярные языки. Можно создавать свои анализаторы.
Views специальные объекты, которые хранят данные о результатах аналитики/индексации
Links объекты связывающие коллекции и views правилами аналитики полей. То есть мы задаём связь с коллекцией и какими анализаторами обрабатывать поля её объектов.

Движок интеграции – слой предоставления данных.
Search – препроцессор, работает над views, может видеть только индексированные поля, то есть такие, которые мы описали в links.
Rank позволяет получить вес результатов, в соответсвии с запросом на поиск. Также можем ставить свои веса для частей поиска.

Пример поиска слова "ninja" в описании фильмa:

FOR doc in view
  SEARCH ANALYZER(d.description == "ninja", "text_en")
  RETURN doc