H.1. apache_age — функциональность графовой базы данных #
- H.1.1. Установка и подготовка
- H.1.2. Графы
- H.1.3. Формат Cypher-запроса в apache_age
- H.1.4. Типы данных — описание
agtype
- H.1.5. Сопоставимость, равенство, упорядочиваемость и эквивалентность
- H.1.6. Операторы
- H.1.7. Агрегирование
- H.1.8. Импорт графов из файлов
- H.1.9. MATCH
- H.1.10. WITH
- H.1.11. RETURN
- H.1.12. ORDER BY
- H.1.13. SKIP
- H.1.14. LIMIT
- H.1.15. CREATE
- H.1.16. DELETE
- H.1.17. SET
- H.1.18. REMOVE
- H.1.19. MERGE
- H.1.20. Функции-предикаты
- H.1.21. Скалярные функции
- H.1.22. Функции списка
- H.1.23. Числовые функции
- H.1.24. Логарифмические функции
- H.1.25. Тригонометрические функции
- H.1.26. Строковые функции
- H.1.27. Агрегатные функции
- H.1.28. Пользовательские функции
- H.1.29. apache_age за рамками языка Cypher
- H.1.2. Графы
apache_age — это расширение, добавляющее в Postgres Pro функциональность для работы с графовыми базами данных. AGE — акроним выражения A Graph Extension. Цель проекта — создать единое хранилище, способное работать с данными как реляционной, так и графовой модели, чтобы пользователи могли использовать стандартный ANSI SQL вместе с языком запросов к графам openCypher.
Важно
Пользовательские таблицы в базах данных apache_age содержат столбцы, имеющие системные типы данных reg*
, которые ссылаются на OID. В связи с этим обновление основной версии с использованием pg_upgrade не поддерживается.
H.1.1. Установка и подготовка #
Расширение apache_age
поставляется вместе с Postgres Pro Enterprise в виде отдельного пакета apache-age-ent-17
(подробные инструкции по установке приведены в Главе 17). После установки Postgres Pro Enterprise создайте расширение apache_age
:
CREATE EXTENSION age;
Для каждого создаваемого подключения apache_age необходимо загрузить библиотеку apache_age.
LOAD 'age';
Обычные пользователи должны указывать полный путь для загрузки библиотеки apache_age.
LOAD '$libdir/plugins/age.so';
Рекомендуется добавить ag_catalog
к search_path
, чтобы облегчить работу с запросами. В дальнейшем во всём документе предполагается, что это было сделано. Если это не так, не забывайте добавлять ag_catalog
к вызовам функций с запросами на языке Cypher.
SET search_path = ag_catalog, '$user', public;
Чтобы использовать apache_age, обычным пользователям необходимы права USAGE
на схему ag_catalog
(ниже представлен пример для пользователя db_user
):
GRANT USAGE ON SCHEMA ag_catalog TO db_user; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA ag_catalog TO db_user;
H.1.2. Графы #
Граф состоит из совокупности вершин и рёбер, где каждый отдельный узел и ребро обладают ассоциативным массивом свойств. Вершина — это базовый объект графа, который может существовать независимо от всего остального в графе. Ребро создаёт направленное соединение между двумя вершинами.
H.1.2.1. Создание графа #
Для создания графа используйте функцию create_graph
из пространства имён ag_catalog
.
-
create_graph(
#graph_name
text
) returns void Эта функция не возвращает результатов. Если не выводится сообщение об ошибке, граф считается созданным. Необходимые для графа таблицы создаются автоматически.
SELECT * FROM ag_catalog.create_graph('graph_name');
H.1.2.2. Предоставление прав #
Суперпользователь может предоставлять права на отдельные существующие графы обычным пользователям (в следующем примере предоставляются права на граф graph1
пользователю db_user
):
GRANT USAGE ON SCHEMA graph1 TO db_user; GRANT ALL PRIVILEGES ON SCHEMA graph1 TO db_user; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA graph1 TO db_user; GRANT ALL PRIVILEGES ON TABLE graph1._ag_label_vertex TO db_user;
H.1.2.3. Удаление графа #
Для удаления графа используйте функцию drop_graph
из пространства имён ag_catalog
.
-
drop_graph(
#graph_name
text
,cascade
boolean
) returns void Эта функция не возвращает результатов. Если не выводится сообщение об ошибке, граф считается удалённым. Рекомендуется установить значение true для параметра
cascade
, иначе все объекты в графе придётся удалять вручную с помощью DDL-команд SQL.SELECT * FROM ag_catalog.drop_graph('graph_name', true);
H.1.2.4. Хранение графов в Postgres Pro #
При создании графов с помощью apache_age для каждого отдельного графа создаётся пространство имён Postgres Pro. Имена и пространства имён созданных графов можно увидеть в таблице ag_graph
пространства имён ag_catalog
:
SELECT create_graph('new_graph'); NOTICE: graph 'new_graph' has been created create_graph -------------- (1 row) SELECT * FROM ag_catalog.ag_graph; name | namespace -----------+----------- new_graph | new_graph (1 row)
После создания графа в его пространстве имён будут созданы две таблицы для хранения вершин и рёбер: _ag_label_vertex
и _ag_label_edge
. Они будут родительскими таблицами для любой новой метки вершины или ребра. В запросе ниже показано, как получить метки рёбер и вершин для всех графов в базе данных.
-- До создания новой метки вершины. SELECT * FROM ag_catalog.ag_label; name | graph | id | kind | relation | seq_name ------------------+-------+----+------+----------------------------+------------------------- _ag_label_vertex | 68484 | 1 | v | new_graph._ag_label_vertex | _ag_label_vertex_id_seq _ag_label_edge | 68484 | 2 | e | new_graph._ag_label_edge | _ag_label_edge_id_seq (2 rows) -- Создание новой метки вершины. SELECT create_vlabel('new_graph', 'Person'); NOTICE: VLabel 'Person' has been created create_vlabel --------------- (1 row) -- После создания новой метки вершины. SELECT * FROM ag_catalog.ag_label; name | graph | id | kind | relation | seq_name ------------------+-------+----+------+----------------------------+------------------------- _ag_label_vertex | 68484 | 1 | v | new_graph._ag_label_vertex | _ag_label_vertex_id_seq _ag_label_edge | 68484 | 2 | e | new_graph._ag_label_edge | _ag_label_edge_id_seq Person | 68484 | 3 | v | new_graph.'Person' | Person_id_seq (3 rows)
При создании метки вершины функцией create_vlabel()
в пространстве имён new_graph
создаётся новая таблица: new_graph.'
. То же самое происходит при создании меток рёбер функцией метка
'create_elabel()
. При создании вершин и рёбер с помощью языка Cypher эти таблицы создаются автоматически.
-- Создание двух вершин и одного ребра. SELECT * FROM cypher('new_graph', $$ CREATE (:Person {name: 'Daedalus'})-[:FATHER_OF]->(:Person {name: 'Icarus'}) $$) AS (a agtype); a --- (0 rows) -- Вывод новых созданных таблиц. SELECT * FROM ag_catalog.ag_label; name | graph | id | kind | relation | seq_name ------------------+-------+----+------+----------------------------+------------------------- _ag_label_vertex | 68484 | 1 | v | new_graph._ag_label_vertex | _ag_label_vertex_id_seq _ag_label_edge | 68484 | 2 | e | new_graph._ag_label_edge | _ag_label_edge_id_seq Person | 68484 | 3 | v | new_graph.'Person' | Person_id_seq FATHER_OF | 68484 | 4 | e | new_graph.'FATHER_OF' | FATHER_OF_id_seq (4 rows)
Примечание
Не рекомендуется выполнять команды DML или DDL в пространстве имён, зарезервированном для графа.
H.1.3. Формат Cypher-запроса в apache_age #
Cypher-запросы создаются с использованием функции cypher
в ag_catalog
, которая возвращает в Postgres Pro SETOF record.
-
cypher(
#graph_name
name
,query_string
cstring
,parameters
agtype
) returns setof record Выполняет Cypher-запрос, переданный в виде аргумента. Если Cypher-запрос не возвращает результатов, всё равно необходимо задать определение записи. Ассоциативный массив параметров, заданный как
parameters
, может использоваться только с подготовленными операторами. В противном случае выводится ошибка.SELECT * FROM cypher('graph_name', $$ /* Cypher Query Here */ $$) AS (result1 agtype, result2 agtype);
H.1.3.1. Язык Cypher в выражении #
Язык Cypher нельзя использовать как часть выражения, вместо этого следует использовать подзапрос. Для получения дополнительной информации о том, как использовать Cypher-запросы с выражениями, обратитесь к разделу Расширенные Cypher-запросы.
H.1.3.2. Предложение SELECT #
Вызывать язык Cypher в качестве независимого столбца в предложении SELECT
не допускается. Однако Cypher может использоваться в качестве условного выражения.
SELECT cypher('graph_name', $$ MATCH (v:Person) RETURN v.name $$); ERROR: cypher(...) in expressions is not supported LINE 3: cypher('graph_name', $$ ^ HINT: Use subquery instead if possible.
H.1.4. Типы данных — описание agtype
#
apache_age использует собственный тип данных под названием agtype
и возвращает только его. Тип agtype
— это надмножество json
и вариант реализации jsonb
.
H.1.4.1. Простые типы данных #
H.1.4.1.1. Тип null #
В языке Cypher null
используется для обозначения отсутствующих или неопределённых значений. Концептуально null
означает «отсутствующее неизвестное значение» и обрабатывается несколько иначе, чем другие значения. Например, при попытке получить свойство из вершины, не имеющей указанного свойства, возвращается null
. Большинство выражений, которые принимают null
в качестве входных данных, вернут null
. Это касается и логических выражений, которые используются в качестве предикатов в предложении WHERE
. В этом случае всё, что не является true, интерпретируется как false. null
не равен null
. Неизвестные значения не считаются равными. Таким образом, выражение null = null
выдаёт null
и не является true.
Следующий запрос возвращает null
как пустой результат.
SELECT * FROM cypher('graph_name', $$ RETURN NULL $$) AS (null_result agtype); null_result -------------- (1 row)
Концепция NULL
в agtype
и Postgres Pro совпадает с Cypher.
H.1.4.1.2. Тип integer #
Тип integer
хранит целые числа, то есть числа без дробных составляющих. Целочисленный тип данных — это 64-битное поле, в котором хранятся значения от -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807. Попытки сохранить значения за пределами этого диапазона приведут к ошибке.
Чаще всего используется тип integer
, как наиболее сбалансированный с точки зрения ширины диапазона, размера и быстродействия. Тип smallint
обычно применяется, только когда крайне важно уменьшить размер данных на диске. Тип bigint
предназначен для тех случаев, когда числа не умещаются в диапазон типа integer
.
SELECT * FROM cypher('graph_name', $$ RETURN 1 $$) AS (int_result agtype); int_result -------------- 1 (1 row)
H.1.4.1.3. Тип float #
Тип данных float
используется для приближённых числовых значений с переменной точностью, соответствующих стандарту IEEE 754.
Переменная точность здесь выражается в том, что некоторые значения, которые нельзя преобразовать во внутренний формат, сохраняются приближённо, так что полученное значение может несколько отличаться от записанного. Управление подобными расхождениями и их распространение в процессе вычислений являются предметом изучения целых разделов математики и информатики, и здесь не рассматривается. Однако следует отметить следующее:
Если нужна точность данных при хранении и вычислениях (например, для денежных сумм), используйте вместо этого тип
numeric
.Если с этими типами выполняются сложные и важные вычисления, тщательно изучите реализацию операций в используемой среде и особенно поведение в особых случаях (бесконечность, антипереполнение).
Проверка равенства двух чисел с плавающей точкой может не всегда давать ожидаемый результат.
Попытка сохранить слишком большие или слишком маленькие значения приведёт к ошибке. Если точность вводимого числа слишком велика, оно будет округлено. При попытке сохранить число, близкое к 0, но непредставимое как отличное от 0, произойдёт ошибка антипереполнения.
Помимо обычных числовых (numeric) значений, в типах с плавающей точкой есть несколько специальных значений:
Infinity
-Infinity
NaN
Они представляют собой специальные значения IEEE 754 «бесконечность», «отрицательная бесконечность» и «не-число» соответственно. При записи этих значений в качестве констант на языке Cypher нужно заключать их в кавычки и приводить к типу, например:
SET x.float_value = '-Infinity'::float
При вводе эти строки распознаются без учёта регистра.
Примечание
Обратите внимание, что IEEE 754 указывает, что NaN не следует сравнивать с любым другим значением с плавающей точкой (включая NaN). Однако, чтобы обеспечить правильную сортировку чисел с плавающей точкой, apache_age считает истинным 'NaN'::float = 'NaN'::float
. За дополнительной информацией обратитесь к разделу Сопоставимость и равенство.
Чтобы использовать число с плавающей точкой, укажите десятичное значение.
SELECT * FROM cypher('graph_name', $$ RETURN 1.0 $$) AS (float_result agtype); float_result -------------- 1.0 (1 row)
H.1.4.1.4. Тип numeric #
Тип numeric
позволяет хранить числа с очень большим количеством цифр. Он особенно рекомендуется для хранения денежных сумм и других величин, где важна точность. Вычисления с типом numeric
дают точные результаты, где это возможно, например, при сложении, вычитании и умножении. Однако операции со значениями numeric
выполняются гораздо медленнее, чем с целыми числами или типами с плавающей точкой.
Ниже мы используем следующие термины: масштаб значения numeric
определяет количество десятичных цифр в дробной части, справа от десятичной точки, а точность — общее количество значимых цифр в числе, т. е. количество цифр по обе стороны десятичной точки. Например, число 23.5141 имеет точность 6 и масштаб 4. Целочисленные значения можно считать числами с масштабом 0.
При указании NUMERIC
без точности и масштаба создаётся столбец, в котором можно сохранять числовые значения любого масштаба и точности до предела, обусловленного реализацией. В столбце этого типа входные значения не будут приводиться к какому-либо масштабу, тогда как в столбцах numeric
с явно заданным масштабом значения подгоняются под этот масштаб. (Стандарт SQL утверждает, что по умолчанию должен устанавливаться масштаб 0, т. е. значения должны приводиться к целым числам. Однако мы считаем это не очень полезным. Если для вас важна переносимость, всегда указывайте точность и масштаб явно.)
Примечание
Максимально допустимая точность, которую можно указать в объявлении типа, равна 1000; если же использовать NUMERIC
без указания точности, действуют ограничения, описанные в Таблице 8.2.
Если масштаб значения, которое нужно сохранить, превышает объявленный масштаб столбца, система округлит его до заданного количества цифр после точки. Если же после этого количество цифр слева в сумме с масштабом превысит объявленную точность, произойдёт ошибка.
Числовые значения физически хранятся без каких-либо дополняющих нулей слева или справа. Таким образом, объявляемые точность и масштаб столбца определяют максимальный, а не фиксированный размер хранения. (В этом смысле тип numeric
больше похож на тип varchar(
, чем на n
)char(
.) Действительный размер хранения такого значения складывается из двух байт для каждой группы из четырёх цифр и дополнительных трёх-восьми байт.n
)
Помимо обычных чисел тип numeric
позволяет использовать специальное значение NaN
, что означает «not-a-number» (не число). Любая операция c NaN
выдаёт в результате тоже NaN
. Записывая это значение в виде константы в команде SQL, его нужно заключать в апострофы, например так: UPDATE table SET x = 'NaN'
. Регистр символов в строке NaN
не важен.
Примечание
В большинстве реализаций «не число» (NaN
) считается не равным любому другому значению (в том числе и самому NaN
). Чтобы можно было сортировать числа с плавающей точкой, apache_age вычисляет 'NaN'::numeric = 'NaN':numeric
как true. За дополнительной информацией обратитесь к разделу Сопоставимость и равенство.
При округлении значений тип numeric
выдаёт число, большее по модулю, тогда как (на большинстве платформ) типы real
и double precision
выдают ближайшее чётное число.
При создании типа данных numeric
требуется аннотация данных ::numeric
.
SELECT * FROM cypher('graph_name', $$ RETURN 1.0::numeric $$) AS (numeric_result agtype); numeric_result -------------- 1.0::numeric (1 row)
H.1.4.1.5. Логические значения #
В apache_age есть стандартный Cypher-тип boolean
. Тип boolean
может иметь следующие состояния: true
, false
и третье состояние, unknown
, которое представляется значением null
типа agtype
.
Логические константы могут быть представлены в Cypher-запросах следующими ключевыми словами: TRUE
, FALSE
и NULL
.
SELECT * FROM cypher('graph_name', $$ RETURN TRUE $$) AS (boolean_result agtype); boolean_result -------------- true (1 row)
В отличие от Postgres Pro, в apache_age логические значения выводятся как полное слово, т. е. true
и false
, а не t
и f
.
H.1.4.1.6. Тип string #
Строковые литералы agtype
могут содержать следующие спецпоследовательности:
Таблица H.1. Спецпоследовательности
Спецпоследовательность | Символ |
---|---|
\t | Табуляция |
\b | Забой |
\n | Новая строка |
\r | Возврат каретки |
\f | Подача формы |
\' | Апостроф |
\" | Двойная кавычка |
\\ | Обратная косая черта |
\uXXXX | Кодовая точка Unicode UTF-16 (4 шестнадцатеричные цифры должны следовать за \u ) |
Используйте апостроф (') для определения строки. В выводе будут использоваться двойные (") кавычки.
SELECT * FROM cypher('graph_name', $$ RETURN 'This is a string' $$) AS (string_result agtype); string_result -------------- "This is a string" (1 row)
H.1.4.2. Составные типы данных #
H.1.4.2.1. Список #
Во всех примерах будут использоваться предложения WITH
и RETURN
.
Буквальный список создаётся с помощью скобок и разделения элементов списка запятыми.
SELECT * FROM cypher('graph_name', $$ WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as lst RETURN lst $$) AS (lst agtype); lst ------------------------------------ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] (1 row)
Список может содержать значение null
, но в отличие от независимого значения null
, оно будет отображаться в списке как слово null
.
SELECT * FROM cypher('graph_name', $$ WITH [null] as lst RETURN lst $$) AS (lst agtype); lst -------- [null] (1 row)
Для доступа к отдельным элементам списка также используются квадратные скобки. Значения будут извлекаться от начального индекса до конечного индекса, не включая последний.
SELECT * FROM cypher('graph_name', $$ WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as lst RETURN lst[3] $$) AS (element agtype); element --------- 3 (1 row)
Элементы ассоциативного массива в списках:
SELECT * FROM cypher('graph_name', $$ WITH [0, {key: 'key_value'}, 2, 3, 4, 5, 6, 7, 8, 9, 10] as lst RETURN lst $$) AS (map_value agtype); map_value ------------------------------------------------------- [0, {"key": "key_value"}, 2, 3, 4, 5, 6, 7, 8, 9, 10] (1 row)
Обращение к элементам ассоциативного массива в списках:
SELECT * FROM cypher('graph_name', $$ WITH [0, {key: 'key_value'}, 2, 3, 4, 5, 6, 7, 8, 9, 10] as lst RETURN lst[1].key $$) AS (map_value agtype); map_value ------------- "key_value" (1 row)
Также можно использовать отрицательные числа, чтобы начать с конца списка.
SELECT * FROM cypher('graph_name', $$ WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as lst RETURN lst[-3] $$) AS (element agtype); element --------- 8 (1 row)
Наконец, можно использовать диапазоны внутри скобок для возвращения диапазонов из списка.
SELECT * FROM cypher('graph_name', $$ WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as lst RETURN lst[0..3] $$) AS (element agtype); element ----------- [0, 1, 2] (1 row)
Отрицательные диапазоны индексов:
SELECT * FROM cypher('graph_name', $$ WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as lst RETURN lst[0..-5] $$) AS (lst agtype); lst -------------------- [0, 1, 2, 3, 4, 5] (1 row)
Положительные срезы:
SELECT * FROM cypher('graph_name', $$ WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as lst RETURN lst[..4] $$) AS (lst agtype); lst -------------- [0, 1, 2, 3] (1 row)
Отрицательные срезы:
SELECT * FROM cypher('graph_name', $$ WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as lst RETURN lst[-5..] $$) AS (lst agtype); lst ------------------ [6, 7, 8, 9, 10] (1 row)
Срезы, выходящие за пределы, просто усекаются, но отдельные элементы, выходящие за пределы, возвращают null.
SELECT * FROM cypher('graph_name', $$ WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as lst RETURN lst[15] $$) AS (element agtype); element --------- (1 row)
SELECT * FROM cypher('graph_name', $$ WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as lst RETURN lst[5..15] $$) AS (element agtype); element --------------------- [5, 6, 7, 8, 9, 10] (1 row)
H.1.4.2.2. Ассоциативный массив #
С помощью Cypher можно строить ассоциативные массивы.
Можно создать простой ассоциативный массив с простыми значениями типа agtype
.
SELECT * FROM cypher('graph_name', $$ WITH {int_key: 1, float_key: 1.0, numeric_key: 1::numeric, bool_key: true, string_key: 'Value'} as m RETURN m $$) AS (m agtype); m ------------------------------------------------------------------------------------------------------ {"int_key": 1, "bool_key": true, "float_key": 1.0, "string_key": "Value", "numeric_key": 1::numeric} (1 row)
Ассоциативный массив также может содержать составные типы данных, то есть списки и другие ассоциативные массивы.
SELECT * FROM cypher('graph_name', $$ WITH {listKey: [{inner: 'Map1'}, {inner: 'Map2'}], mapKey: {i: 0}} as m RETURN m $$) AS (m agtype); m ------------------------------------------------------------------------- {"mapKey": {"i": 0}, "listKey": [{"inner": "Map1"}, {"inner": "Map2"}]} (1 row)
Обращение к свойствам ассоциативного массива:
SELECT * FROM cypher('graph_name', $$ WITH {int_key: 1, float_key: 1.0, numeric_key: 1::numeric, bool_key: true, string_key: 'Value'} as m RETURN m.int_key $$) AS (int_key agtype); int_key --------- 1 (1 row)
Доступ к элементам списка в ассоциативных массивах:
SELECT * FROM cypher('graph_name', $$ WITH {listKey: [{inner: 'Map1'}, {inner: 'Map2'}], mapKey: {i: 0}} as m RETURN m.listKey[0] $$) AS (m agtype); m ------------------- {"inner": "Map1"} (1 row)
H.1.4.3. Простые сущности #
Сущность имеет уникальную, сравниваемую идентичность, которая определяет, равны ли две сущности.
Сущности присваивается набор свойств, каждое из которых уникально идентифицируется в наборе соответствующими ключами свойств.
H.1.4.3.1. Идентификатор графа #
Простым сущностям присваивается уникальный идентификатор графа (graphid
). graphid
— это уникальное сочетание идентификатора метки сущности и уникальной последовательности, присвоенной каждой метке. Обратите внимание, что у сущностей из разных графов могут быть одинаковые идентификаторы.
Метка — это идентификатор, который классифицирует вершины и рёбра по определённым категориям.
Рёбра должны иметь метку, а вершины — нет.
Имена меток вершин и рёбер не могут совпадать.
Обратитесь к описанию предложения CREATE
, чтобы узнать, как создавать объекты с метками.
И вершины, и рёбра могут иметь свойства. Свойства представляют собой значения атрибутов, и каждое имя атрибута должно быть строкового типа.
H.1.4.4. Вершина #
Вершина — это базовая сущность графа, которая может существовать сама по себе.
Вершине может быть присвоена метка.
У вершины может быть ноль или более исходящих рёбер.
У вершины может быть ноль или более входящих рёбер.
Таблица H.2. Формат данных
Имя атрибута | Описание |
---|---|
id | Идентификатор графа для данной вершины |
label | Имя метки данной вершины |
properties | Свойства, присвоенные данной вершине |
{id:1; label: 'label_name'; properties: {prop1: value1, prop2: value2}}::vertex
Приведение ассоциативного массива к вершине:
SELECT * FROM cypher('graph_name', $$ WITH {id: 0, label: 'label_name', properties: {i: 0}}::vertex as v RETURN v $$) AS (v agtype); v ------------------------------------------------------------------ {"id": 0, "label": "label_name", "properties": {"i": 0}}::vertex (1 row)
H.1.4.5. Ребро #
Ребро — это сущность, которая представляет собой направленное соединение между двумя узлами: исходным узлом и целевым узлом. Исходящее ребро — это направленная связь с точки зрения исходного узла. Входящее ребро — это направленная связь с точки зрения целевого узла. Ребру присваивается только один тип ребра.
Таблица H.3. Формат данных
Имя атрибута | Описание |
---|---|
id | Идентификатор графа для данного ребра |
startid | Идентификатор графа исходного узла |
endid | Идентификатор графа целевого узла |
label | Имя метки данной вершины |
properties | Свойства, присвоенные данной вершине |
{id: 3; startid: 1; endid: 2; label: 'edge_label' properties{prop1: value1, prop2: value2}}::edge
Приведение ассоциативного массива к ребру:
SELECT * FROM cypher('graph_name', $$ WITH {id: 2, start_id: 0, end_id: 1, label: 'label_name', properties: {i: 0}}::edge as e RETURN e $$) AS (e agtype); e -------------------------------------------------------------------------------------------- {"id": 2, "label": "label_name", "end_id": 1, "start_id": 0, "properties": {"i": 0}}::edge (1 row)
H.1.4.6. Составные сущности #
Путь — это серия чередующихся вершин и рёбер. Путь должен начинаться с вершины и иметь хотя бы одно ребро.
Приведение списка к пути:
SELECT * FROM cypher('graph_name', $$ WITH [{id: 0, label: 'label_name_1', properties: {i: 0}}::vertex, {id: 2, start_id: 0, end_id: 1, label: 'edge_label', properties: {i: 0}}::edge, {id: 1, label: 'label_name_2', properties: {}}::vertex ]::path as p RETURN p $$) AS (p agtype); p -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [{"id": 0, "label": "label_name_1", "properties": {"i": 0}}::vertex, {"id": 2, "label": "edge_label", "end_id": 1, "start_id": 0, "properties": {"i": 0}}::edge, {"id": 1, "label": "label_name_2", "properties": {}}::vertex]::path (1 row)
H.1.5. Сопоставимость, равенство, упорядочиваемость и эквивалентность #
В apache_age уже предусмотрена семантика равенства примитивных типов (логических значений, строк, целых чисел и чисел с плавающей точкой) и ассоциативных массивов. Более того, в Cypher есть возможность сопоставлять и упорядочивать целые числа, числа с плавающей точкой и строки внутри каждого из типов. Однако логика работа со значениями разных типов отличается от логики, используемой в Postgres Pro и спецификации openCypher:
Определяется сопоставимость между значениями разных типов. Отклонение между значениями особенно заметно, когда появляется в рамках вычисления предикатов (в
WHERE
).Запрос с предложением
ORDER BY
будет успешно выполнен, если переданные ему значения имеют разные типы.
Базовая концептуальная модель сложна и несколько противоречива. В результате взаимосвязь между операторами сравнения, равенством, группировкой и предложением ORDER BY
неясна. Согласованность сопоставимости и упорядочиваемости друг с другом, обеспечивается тем, что все типы можно упорядочивать и сопоставлять. Разница между равенством и эквивалентностью, выявляемая указаниями IN
, =
, DISTINCT
и группировкой, в apache_age ограничена проверкой двух экземпляров значения null по отношению друг к другу. В рамках равенства выражение null = null
равно null
. В эквивалентности, используемой DISTINCT
и при группировке значений, два значения null
всегда рассматриваются как одно и то же значение. Однако равенство обрабатывает значения null
по-разному, если они являются элементами списка или значениями ассоциативного массива.
H.1.5.1. Основные понятия #
Спецификация openCypher содержит четыре различные концепции, связанные с равенством и упорядочиванием:
Сопоставимость используется операторами неравенства (>, <, >=, <=) и определяет базовую семантику того, как сравнивать два значения.
Равенство используется операторами равенства (=, <>) и оператором членства в списке (
IN
). Оно определяет базовую семантику, чтобы установить, являются ли два значения одинаковыми в этих контекстах. Равенство также неявно используется ассоциативными массивами констант в шаблонах узлов и отношений, поскольку такие массивы представляют собой просто сокращённое обозначение предикатов равенства.Упорядочиваемость используется предложением
ORDER BY
и определяет базовую семантику того, как упорядочивать значения.Эквивалентность используется модификатором
DISTINCT
и группировкой в предложениях проекций (WITH
,RETURN
) и определяет базовую семантику, позволяющую установить, являются ли два значения в этих контекстах одинаковыми.
H.1.5.2. Сопоставимость и равенство #
Операторы сравнения должны работать так, как и ожидается — равенство и сопоставимость. Но в то же время им необходимо разрешить сортировку данных в столбцах — эквивалентность и упорядочиваемость.
К сожалению, в Postgres Pro может оказаться невозможным реализовать отдельные операторы сравнения для операций сравнения и равенства, а также операций эквивалентности и упорядочиваемости для одного и того же запроса. Поэтому в apache_age отдаётся приоритет эквивалентности и упорядочиваемости над равенством и сопоставимостью, чтобы обеспечить упорядочивание выходных данных.
H.1.5.2.1. Сопоставимость #
Сопоставимость определяется между любой парой значений, как указано ниже.
Числа
Числа разных типов (за исключением значений NaN и бесконечностей) сравниваются друг с другом, как если бы оба числа были приведены к типу
bigdecimal
произвольной точности (в настоящее время вне системы типов Cypher), прежде чем сравниваться в порядке возрастания числовых значений.Сравнение с любым значением, которое не является числом, следует правилам упорядочиваемости.
Числа с плавающей точкой не обладают необходимой точностью для представления всех целых чисел в диапазонах
agtype integer
иagtype numeric
. При приведении значений типаagtype integer
илиagtype numeric
в верхнем и нижнем диапазоне к типуfloat
могут возникнуть непредвиденные результаты.Целые числа (integer)
Целые числа сравниваются в порядке возрастания числовых значений.
Числа с плавающей точкой (float)
Числа с плавающей точкой (за исключением значений NaN и бесконечностей) сравниваются в порядке возрастания числовых значений.
Положительная бесконечность имеет тип
FLOAT
, равна самой себе и больше любого другого числа, кроме значений NaN.Отрицательная бесконечность имеет тип
FLOAT
, равна самой себе и меньше любого другого числа.Значения NaN сопоставимы друг с другом и превышают любое другое значение с плавающей точкой.
Числа (numeric)
Числа сравниваются в порядке возрастания числовых значений.
Логические значения (booleans)
Логические значения сравниваются таким образом, что значение false считается меньше, чем true.
Сравнение с любым значением, которое не является логическим, следует правилам упорядочиваемости.
Строки (string)
Строки сравниваются в словарном порядке, т. е. символы сравниваются попарно в порядке возрастания от начала строки к концу. Символы, отсутствующие в более короткой строке, считаются меньше, чем любой другой символ. Например,
'a' < 'аа'
.Сравнение с любым значением, которое не является строкой, следует правилам упорядочиваемости.
Списки (list)
Списки сравниваются в последовательном порядке, т. е. элементы списка сравниваются попарно в порядке возрастания от начала списка к концу. Элементы, отсутствующие в более коротком списке, считаются меньшими, чем любое другое значение (включая значения
null
), например,[1] < [1, 0]
, но также[1] < [1, null]
.Сравнение с любым значением, которое не является списком, следует правилам упорядочиваемости.
Ассоциативные массивы (map)
Порядок сравнения ассоциативных массивов не определён и зависит от конкретной реализации.
Порядок сравнения ассоциативных массивов должен соответствовать семантике равенства, описанной ниже. Следовательно, любой ассоциативный массив, содержащий запись, которая сопоставляет свой ключ со значением null, является несравниваемым. Например,
{a: 1} <= {a: 1, b: null}
имеет значение null.Сравнение с любым значением, которое не является обычным ассоциативным массивом, следует правилам упорядочиваемости.
Сущности:
Вершины: порядок сравнения вершин основан на присвоенном
graphid
.Рёбра: порядок сравнения рёбер основан на присвоенном
graphid
.Пути: пути сравниваются так, как если бы они были списком чередующихся узлов и отношений пути от начального узла к конечному узлу. Например, если есть узлы
n1
,n2
,n3
и отношенияr1
иr2
, аn1 < n2 < n3
иr1 < r2
, путьp1
отn1
доn3
черезr1
будет меньше путиp2
вn1
отn2
черезr2
. Пути выражаются в виде списков:p1 < p2 <=> [n1, r1, n3] < [n1, r2, n2] <=> n1 < n1 || (n1 = n1 && [r1, n3] < [r2, n2]) <=> false || (true && [r1, n3] < [r2, n2]) <=> [r1, n3] < [r2, n2] <=> r1 < r2 || (r1 = r2 && n3 < n2) <=> true || (false && false) <=> true
Примечание
Сравнение с любым значением, которое не является путём, вернёт false.
NULL:
null
не сравним ни с каким другим значением (включая другие значенияnull
).
H.1.5.3. Упорядочиваемость между различными типами agtype
#
Упорядочивание различных типов agtype
при использовании <, <=, >, >= от наименьшего значения к наибольшему:
Путь
Ребро
Вершина
Объект
Массив
Строка
Логическое значение
Numeric, Integer, Float
NULL
Примечание
Это может измениться в будущих выпусках.
H.1.6. Операторы #
H.1.6.1. Операторы сравнения строк #
SELECT * FROM cypher('graph_name', $$ CREATE (:Person {name: 'John'}), (:Person {name: 'Jeff'}), (:Person {name: 'Joan'}), (:Person {name: 'Bill'}) $$) AS (result agtype);
- STARTS WITH #
Выполняет поиск префиксов по строкам с учётом регистра.
SELECT * FROM cypher('graph_name', $$ MATCH (v:Person) WHERE v.name STARTS WITH "J" RETURN v.name $$) AS (names agtype); names -------- "John" "Jeff" "Joan" (3 rows)
- CONTAINS #
Выполняет поиск включений по строкам с учётом регистра.
SELECT * FROM cypher('graph_name', $$ MATCH (v:Person) WHERE v.name CONTAINS "o" RETURN v.name $$) AS (names agtype); names -------- "John" "Joan" (2 rows)
- ENDS WITH #
Выполняет поиск суффиксов по строкам с учётом регистра.
SELECT * FROM cypher('graph_name', $$ MATCH (v:Person) WHERE v.name ENDS WITH "n" RETURN v.name $$) AS (names agtype); names -------- "John" "Joan" (2 rows)
H.1.6.1.1. Регулярные выражения #
apache_age поддерживает использование регулярных выражений POSIX с применением оператора =~
. По умолчанию =~
чувствителен к регистру.
- Простое соответствие строк #
Оператор
=~
без указания специальных символов действует как оператор=
.SELECT * FROM cypher('graph_name', $$ MATCH (v:Person) WHERE v.name =~ 'John' RETURN v.name $$) AS (names agtype); names -------- "John" (1 row)
- Поиск без учёта регистра #
Если добавить
(?i)
в начало строки, при сравнении не учитывается регистр.SELECT * FROM cypher('graph_name', $$ MATCH (v:Person) WHERE v.name =~ '(?i)JoHn' RETURN v.name $$) AS (names agtype); names -------- "John" (1 row)
- Знак подстановки
.
# Оператор
.
действует как знак подстановки, соответствующий любому отдельному символу.SELECT * FROM cypher('graph_name', $$ MATCH (v:Person) WHERE v.name =~ 'Jo.n' RETURN v.name $$) AS (names agtype); names -------- "John" "Joan" (2 rows)
- Знак подстановки
*
# Знак подстановки
*
соответствует 0 или более вхождениям символа перед этим знаком.SELECT * FROM cypher('graph_name', $$ MATCH (v:Person) WHERE v.name =~ 'Johz*n' RETURN v.name $$) AS (names agtype); names -------- "John" (1 row)
- Оператор
+
# Оператор
+
соответствует одному предыдущему символу или более.SELECT * FROM cypher('graph_name', $$ MATCH (v:Person) WHERE v.name =~ 'Bil+' RETURN v.name $$) AS (names agtype); names -------- "Bill" (1 row)
- Совместное использование знаков подстановки
.
и*
# Можно использовать подстановочные знаки
.
и*
вместе, чтобы заменить оставшуюся часть строки.SELECT * FROM cypher('graph_name', $$ MATCH (v:Person) WHERE v.name =~ 'J.*' RETURN v.name $$) AS (names agtype); names -------- "John" "Jeff" "Joan" (3 rows)
H.1.6.2. Приоритет операторов #
Приоритет операторов в apache_age представлен ниже:
Таблица H.4. Приоритет операторов
Приоритет | Оператор | Описание |
---|---|---|
1 | . | Обращение к свойству |
2 | [] | Обращение по индексу к ассоциативным массивам и спискам |
() | Вызов функций | |
3 | STARTS WITH | Поиск префиксов по строкам с учётом регистра |
ENDS WITH | Поиск суффиксов по строкам с учётом регистра | |
CONTAINS | Поиск включений по строкам регистра в строках | |
=~ | Соответствие строке регулярного выражения | |
4 | - | Унарный минус |
5 | IN | Проверка существования элемента в списке |
IS NULL | Является ли значение NULL | |
IS NOT NULL | Отличается ли значение от NULL | |
6 | ^ | Возведение в степень |
7 | * / % | Умножение, деление и остаток |
8 | + - | Сложение и вычитание |
9 | = <> | Для реляционных = и ≠ соответственно |
< <= | Для реляционных < и ≤ соответственно | |
> >= | Для реляционных > и ≥ соответственно | |
10 | NOT | Логическое НЕ |
11 | AND | Логическое И |
12 | OR | Логическое ИЛИ |
H.1.7. Агрегирование #
Обычно агрегирование aggr(expr)
обрабатывает все совпадающие строки для каждого ключа агрегирования, найденного во входящей записи (ключи сравниваются с использованием эквивалентности).
При обычном агрегировании (т. е. в форме aggr(expr)
) список агрегированных значений представляет собой список значений-кандидатов, из которого удалены все значения null
.
SELECT * FROM cypher('graph_name', $$ CREATE (a:Person {name: 'A', age: 13}), (b:Person {name: 'B', age: 33, eyes: "blue"}), (c:Person {name: 'C', age: 44, eyes: "blue"}), (d1:Person {name: 'D', eyes: "brown"}), (d2:Person {name: 'D'}), (a)-[:KNOWS]->(b), (a)-[:KNOWS]->(c), (a)-[:KNOWS]->(d1), (b)-[:KNOWS]->(d2), (c)-[:KNOWS]->(d2) $$) as (a agtype);
H.1.7.1. Автоматическая группировка #
Для вычисления агрегированных данных в Cypher предусмотрено агрегирование, аналогичное GROUP BY
в SQL.
Агрегатные функции принимают набор значений и вычисляют по ним агрегированное значение. Например, avg()
вычисляет среднее значение нескольких числовых значений, а min()
находит наименьшее числовое или строковое значение в наборе значений. Ниже указывается, что агрегатная функция работает с набором значений, при этом имеется в виду, что они являются результатом применения внутреннего выражения (например, n.age
) ко всем записям в пределах одной группы агрегирования.
Агрегирование можно выполнять по всем совпадающим подграфам или дополнительно разделять путём введения ключей группировки. Это неагрегатные выражения, которые используются для группировки значений, входящих в агрегатные функции.
Допустим, что у нас есть следующий оператор RETURN
:
SELECT * FROM cypher('graph_name', $$ MATCH (v:Person) RETURN v.name, count(*) $$) as (grouping_key agtype, count agtype); grouping_key | count --------------+------- "A" | 1 "D" | 2 "B" | 1 "C" | 1 (4 rows)
У нас есть два возвращаемых выражения: grouping_key
и count(*)
. Первое, grouping_key
, не является агрегатной функцией и поэтому будет ключом группировки. Последнее, count(*)
, представляет собой агрегатное выражение. Соответствующие подграфы будут разделены на разные группы в зависимости от ключа группировки. Затем для этих групп будет запущена агрегатная функция, вычисляющая агрегированное значение для каждой группы.
H.1.7.2. Сортировка по агрегатным функциям #
Чтобы для сортировки набора результатов использовать агрегирование, его следует включить в предложение RETURN
, которое будет использоваться в ORDER BY
.
SELECT * FROM cypher('graph_name', $$ MATCH (me:Person)-[]->(friend:Person) RETURN count(friend), me ORDER BY count(friend) $$) as (friends agtype, me agtype);
H.1.7.3. Агрегирование с DISTINCT #
В агрегировании DISTINCT (т. е. в форме aggr(DISTINCT expr)
) список агрегированных значений представляет собой список значений-кандидатов, из которого удалены все значения null
. Кроме того, при агрегировании DISTINCT только одно из всех эквивалентных значений-кандидатов включается в список агрегированных значений, т. е. дубликаты при эквивалентности удаляются.
Оператор DISTINCT
работает совместно с агрегированием. Он используется для того, чтобы сделать все значения уникальными перед их использованием в агрегатной функции.
SELECT * FROM cypher('graph_name', $$ MATCH (v:Person) RETURN count(DISTINCT v.eyes), count(v.eyes) $$) as (distinct_eyes agtype, eyes agtype); distinct_eyes | eyes ---------------+------ 2 | 3 (1 row)
H.1.7.4. Неоднозначная группировка #
При использовании операторов, не требующих от пользователя указания ключей группировки для запроса, Cypher может неоднозначно воспринимать, что именно следует квалифицировать как ключ группировки.
SELECT * FROM cypher('graph_name', $$ CREATE (:L {a: 1, b: 2, c: 3}), (:L {a: 2, b: 3, c: 1}), (:L {a: 3, b: 1, c: 2}) $$) as (a agtype);
H.1.7.4.1. Недопустимые запросы в apache_age #
В apache_age для столбца WITH
или RETURN
запрещается комбинировать переменные с агрегатными функциями, которые явно не указаны в другом столбце того же предложения WITH
или RETURN
.
SELECT * FROM cypher('graph_name', $$ MATCH (x:L) RETURN x.a + count(*) + x.b + count(*) + x.c $$) as (a agtype); ERROR: 'x' must be either part of an explicitly listed key or used inside an aggregate function LINE 3: RETURN x.a + count(*) + x.b + count(*) + x.c
H.1.7.4.2. Допустимые запросы в apache_age #
Столбцы, которые не включают агрегатную функцию в apache_age, считаются ключами группировки для этого предложения WITH
или RETURN
.
Приведённый выше запрос можно переписать несколькими способами, которые вернут результаты.
SELECT * FROM cypher('graph_name', $$ MATCH (x:L) RETURN (x.a + x.b + x.c) + count(*) + count(*), x.a + x.b + x.c $$) as (count agtype, key agtype); count | key -------+----- 12 | 6 (1 row)
x.a + x.b + x.c
— это ключ группировки. Созданные таким образом ключи группировки должны включать круглые скобки.
SELECT * FROM cypher('graph_name', $$ MATCH (x:L) RETURN x.a + count(*) + x.b + count(*) + x.c, x.a, x.b, x.c $$) as (count agtype, a agtype, b agtype, c agtype); count | a | b | c -------+---+---+--- 10 | 3 | 1 | 2 10 | 2 | 3 | 1 10 | 1 | 2 | 3 (3 rows)
x.a
, x.b
и x.c
считаются разными ключами группировки.
H.1.7.4.3. Вершины и рёбра в неоднозначной группировке #
В качестве альтернативы ключом группировки может быть вершина или ребро, а затем любые свойства вершины или ребра могут быть заданы без явного указания в столбце WITH
или RETURN
.
SELECT * FROM cypher('graph_name', $$ MATCH (x:L) RETURN count(*) + count(*) + x.a + x.b + x.c, x $$) as (count agtype, key agtype); count | key -------+---------------------------------------------------------------------------------------- 8 | {"id": 1407374883553283, "label": "L", "properties": {"a": 3, "b": 1, "c": 2}}::vertex 8 | {"id": 1407374883553281, "label": "L", "properties": {"a": 1, "b": 2, "c": 3}}::vertex 8 | {"id": 1407374883553282, "label": "L", "properties": {"a": 2, "b": 3, "c": 1}}::vertex (3 rows)
Результаты будут сгруппированы по x
, поскольку можно предположить, что ненужные для группировки свойства являются однозначными.
H.1.7.4.4. Скрытие нежелательных ключей группировки #
Если ключ группировки считается ненужным для вывода запроса, агрегирование можно выполнить в предложении WITH
, а затем передать информацию в предложение RETURN
.
SELECT * FROM cypher('graph_name', $$ MATCH (x:L) WITH count(*) + count(*) + x.a + x.b + x.c as column, x RETURN column $$) as (a agtype); a --- 8 8 8 (3 rows)
H.1.8. Импорт графов из файлов #
Создание графов из файлов описано в следующих разделах:
Примечание
Пользователь должен создать граф и метки перед загрузкой данных из файлов.
H.1.8.1. Функции для загрузки графа #
Ниже приведены подробные сведения о функциях для загрузки вершин и рёбер из файла.
Функция load_labels_from_file
используется для загрузки вершин из CSV-файлов.
load_labels_from_file('имя_графа
', 'имя_метки
', 'путь_к_файлу
')
При добавлении четвёртого параметра пользователь может исключить поле id
. Следует использовать, если в файле нет поля id
.
load_labels_from_file('имя_графа
', 'имя_метки
', 'путь_к_файлу
', false)
Функцию load_edges_from_file
можно использовать для загрузки рёбер из CSV-файла. Структура файла представлена ниже.
Примечание
Убедитесь, что идентификаторы в файле с описанием рёбер идентичны идентификаторам в файлах с описанием вершин.
load_edges_from_file('имя_графа
', 'имя_метки
', 'путь_к_файлу
');
H.1.8.2. Пояснения к формату CSV #
Ниже описывается структура CSV-файлов для вершин и рёбер.
CSV-файл для узлов должен иметь следующий вид:
Таблица H.5. Формат CSV-файла для узлов
Имя поля | Описание поля |
---|---|
id | Первый столбец файла, все значения в котором — положительные целые числа. Это необязательное поле, если id_field_exists имеет значение false . Однако оно должно присутствовать, если для id_field_exists не установлено значение false . |
Свойства | Во всех остальных столбцах содержатся свойства узлов. Строка заголовка содержит имя свойства. |
Подобным образом, CSV-файл для рёбер должен иметь следующий вид:
Таблица H.6. Формат CSV-файла для рёбер
Имя поля | Описание поля |
---|---|
start_id | Идентификатор узла, из которого начинается ребро. Этот идентификатор присутствует в файле nodes.csv . |
start_vertex_type | Класс узла |
end_id | Конечный идентификатор узла, в котором заканчивается ребро. |
end_vertex_type | Класс узла |
properties | Свойства ребра. Заголовок содержит имя свойства. |
H.1.8.3. Пример SQL-скрипта #
Загрузите apache_age и создайте граф.
LOAD 'age'; SET search_path TO ag_catalog; SELECT create_graph('agload_test_graph');
Создайте метку
Country
и загрузите вершины из CSV-файла. Обратите внимание, что в этом CSV-файле есть полеid
.SELECT create_vlabel('agload_test_graph','Country'); SELECT load_labels_from_file('agload_test_graph', 'Country', '/age/regress/age_load/data/countries.csv');
Создайте метку
City
и загрузите вершины из CSV-файла. Обратите внимание, что в этом CSV-файле есть полеid
.SELECT create_vlabel('agload_test_graph','City'); SELECT load_labels_from_file('agload_test_graph', 'City', '/age/regress/age_load/data/cities.csv');
Создайте метку
has_city
и загрузите рёбра из CSV-файла.SELECT create_elabel('agload_test_graph','has_city'); SELECT load_edges_from_file('agload_test_graph', 'has_city', '/age/regress/age_load/data/edges.csv');
Проверьте, правильно ли загружен граф.
SELECT table_catalog, table_schema, table_name, table_type FROM information_schema.tables WHERE table_schema = 'agload_test_graph'; SELECT COUNT(*) FROM agload_test_graph."Country"; SELECT COUNT(*) FROM agload_test_graph."City"; SELECT COUNT(*) FROM agload_test_graph."has_city"; SELECT COUNT(*) FROM cypher('agload_test_graph', $$MATCH(n) RETURN n$$) as (n agtype); SELECT COUNT(*) FROM cypher('agload_test_graph', $$MATCH (a)-[e]->(b) RETURN e$$) as (n agtype);
H.1.8.3.1. Создание вершин без поля идентификатора в файле #
Создайте метку
Country2
и загрузите вершины из CSV-файла. Обратите внимание, что в этом CSV-файле нет поляid
.SELECT create_vlabel('agload_test_graph','Country2'); SELECT load_labels_from_file('agload_test_graph', 'Country2', '/age/regress/age_load/data/countries.csv', false);
Создайте метку
City2
и загрузите вершины из CSV-файла. Обратите внимание, что в этом CSV-файле нет поляid
.SELECT create_vlabel('agload_test_graph','City2'); SELECT load_labels_from_file('agload_test_graph', 'City2', '/age/regress/age_load/data/cities.csv', false);
Проверьте, правильно ли загружен граф, и сравните автоматически созданные идентификаторы и идентификаторы, выбранные из файлов.
Метки
Country
иCity
были созданы при наличии поляid
в файле.Метки
Country2
иCity2
были созданы при отсутствии поляid
в файле.SELECT COUNT(*) FROM agload_test_graph."Country2"; SELECT COUNT(*) FROM agload_test_graph."City2"; SELECT id FROM agload_test_graph."Country" LIMIT 10; SELECT id FROM agload_test_graph."Country2" LIMIT 10; SELECT * FROM cypher('agload_test_graph', $$MATCH(n:Country {iso2 : 'BE'}) RETURN id(n), n.name, n.iso2 $$) as ('id(n)' agtype, 'n.name' agtype, 'n.iso2' agtype); SELECT * FROM cypher('agload_test_graph', $$MATCH(n:Country2 {iso2 : 'BE'}) RETURN id(n), n.name, n.iso2 $$) as ('id(n)' agtype, 'n.name' agtype, 'n.iso2' agtype); SELECT * FROM cypher('agload_test_graph', $$MATCH(n:Country {iso2 : 'AT'}) RETURN id(n), n.name, n.iso2 $$) as ('id(n)' agtype, 'n.name' agtype, 'n.iso2' agtype); SELECT * FROM cypher('agload_test_graph', $$MATCH(n:Country2 {iso2 : 'AT'}) RETURN id(n), n.name, n.iso2 $$) as ('id(n)' agtype, 'n.name' agtype, 'n.iso2' agtype); SELECT drop_graph('agload_test_graph', true);
H.1.9. MATCH #
Предложение MATCH
позволяет указывать шаблоны, по которым Cypher будет искать в базе данных. Это основной способ получения данных в текущий набор связываний. Подробнее ознакомиться со спецификацией самих шаблонов можно в Разделе 9.7.
MATCH
часто сочетается с частью WHERE
, которая добавляет ограничения или предикаты к шаблонам MATCH
, делая их более конкретными. Предикаты являются частью описания шаблона, и их не следует рассматривать как фильтр, применяемый только после завершения сопоставления. Это означает, что часть WHERE
всегда следует объединять с предложением MATCH
, которому она принадлежит.
MATCH
может встречаться в начале запроса или далее, например после WITH
. Если это первое предложение, элементы пока не связаны, и Cypher выстраивает поиск так, чтобы найти результаты, совпадающие с этим предложением и любыми соответствующими ему предикатами, которые указаны в любой части WHERE
. Вершины и рёбра, найденные в результате этого поиска, доступны как связанные элементы шаблона и могут использоваться для сопоставления шаблонов подграфов. Их также можно использовать в любых будущих предложениях, где Cypher будет использовать известные элементы, а затем находить новые неизвестные элементы.
Cypher является декларативным языком, поэтому обычно в самом запросе не определяется алгоритм, который будет использоваться для выполнения поиска. Предикаты в частях WHERE
могут вычисляться перед сопоставлением с шаблоном, во время сопоставления с шаблоном или после обнаружения совпадений.
H.1.9.1. Базовый поиск вершин #
H.1.9.1.1. Получение всех вершин #
Если указать шаблон с одной вершиной и без меток, будут возвращены все вершины графа.
SELECT * FROM cypher('graph_name', $$ MATCH (v) RETURN v $$) as (v agtype); v ------------------------------------------------------------------------------- {id: 0; label: 'Person'; properties: {name: 'Charlie Sheen'}}::vertex {id: 1; label: 'Person'; properties: {name: 'Martin Sheen'}}::vertex {id: 2; label: 'Person'; properties: {name: 'Michael Douglas'}}::vertex {id: 3; label: 'Person'; properties: {name: 'Oliver Stone'}}::vertex {id: 4; label: 'Person'; properties: {name: 'Rob Reiner'}}::vertex {id: 5; label: 'Movie'; properties: {name: 'Wall Street'}}::vertex {id: 6; label: 'Movie'; properties: {title: 'The American President'}}::vertex (7 rows)
Возвращает все вершины в базе данных.
H.1.9.1.2. Получение всех вершин с меткой #
Получить все вершины с метками можно с помощью одного шаблона узла, в котором у вершины есть метка.
SELECT * FROM cypher('graph_name', $$ MATCH (movie:Movie) RETURN movie.title $$) as (title agtype); title ------------------------ 'Wall Street' 'The American President' (2 rows)
Возвращает все фильмы в базе данных.
H.1.9.1.3. Связанные вершины #
Символ -[]-
означает «связанный с», независимо от типа или направления ребра.
SELECT * FROM cypher('graph_name', $$ MATCH (director {name: 'Oliver Stone'})-[]-(movie) RETURN movie.title $$) as (title agtype); title ------------- 'Wall Street' (1 row)
Возвращает все фильмы режиссёра «Oliver Stone».
H.1.9.1.4. Сопоставление с метками #
Чтобы шаблон применялся только к меткам на вершинах, добавьте его к нужной вершине в шаблоне, используя синтаксис меток.
SELECT * FROM cypher('graph_name', $$ MATCH (:Person {name: 'Oliver Stone'})-[]-(movie:Movie) RETURN movie.title $$) as (title agtype); title ------------- 'Wall Street' (1 row)
Возвращает любые вершины, связанные с Person
«Oliver», у которых есть метка Movie
.
H.1.9.2. Поиск по рёбрам #
H.1.9.2.1. Исходящие рёбра #
Направление ребра показывается с помощью ->
или <-
.
SELECT * FROM cypher('graph_name', $$ MATCH (:Person {name: 'Oliver Stone'})-[]->(movie) RETURN movie.title $$) as (title agtype); title ------------- 'Wall Street' (1 row)
Возвращает любые вершины, соединённые с Person
«Oliver» исходящим ребром.
H.1.9.2.2. Направленные рёбра и использование переменной #
Если либо для фильтрации по свойствам ребра, либо для возвращения ребра требуется переменная, её следует вводить следующим образом.
SELECT * FROM cypher('graph_name', $$ MATCH (:Person {name: 'Oliver Stone'})-[r]->(movie) RETURN type(r) $$) as (title agtype); title ---------- 'DIRECTED' (1 row)
Возвращает тип каждого ребра, исходящего из вершины «Oliver».
H.1.9.2.3. Сопоставление по типу ребра #
Если известен тип ребра для сопоставления, можно указать этот тип с двоеточием перед ним.
SELECT * FROM cypher('graph_name', $$ MATCH (:Movie {title: 'Wall Street'})<-[:ACTED_IN]-(actor) RETURN actor.name $$) as (actors_name agtype); actors_name ----------------- 'Charlie Sheen' 'Martin Sheen' 'Michael Douglas' (3 rows)
Возвращает всех актёров, которые играли (ACTED_IN
) в фильме «Wall Street».
H.1.9.2.4. Сопоставление по типу ребра и использование переменной #
Можно одновременно ввести переменную для хранения ребра и указать нужный тип ребра.
SELECT * FROM cypher('graph_name', $$ MATCH ({title: 'Wall Street'})<-[r:ACTED_IN]-(actor) RETURN r.role $$) as (role agtype); role -------------- 'Gordon Gekko' 'Carl Fox' 'Bud Fox' (3 rows)
Возвращает роли актёров, игравших (ACTED_IN
) в фильме «Wall Street».
H.1.9.2.5. Несколько рёбер #
Рёбра можно отобразить, используя несколько операторов в форме ()-[]-()
или объединить их вместе.
SELECT * FROM cypher('graph_name', $$ MATCH (charlie {name: 'Charlie Sheen'})-[:ACTED_IN]->(movie)<-[:DIRECTED]-(director) RETURN movie.title, director.name $$) as (title agtype, name agtype); title | name --------------+-------------- 'Wall Street' | 'Oliver Stone' (1 row)
Возвращает фильм, в котором снимался «Charlie Sheen», и имя режиссёра этого фильма.
H.1.9.3. Рёбра переменной длины #
Когда соединение между двумя вершинами имеет переменную длину, список рёбер, образующих соединение, можно вернуть, используя следующее соединение.
Вместо описания длинного пути с последовательностью описаний множества вершин и рёбер в шаблоне многие рёбра (и промежуточные вершины) можно описать, указав длину в описании ребра в шаблоне.
(u)-[*2]->(v)
Такой шаблон, описывающий направленный вправо путь из трёх вершин и двух рёбер, можно переписать так:
(u)-[]->()-[]->(v)
Также можно указать длину диапазона:
(u)-[*3..5]->(v)
Что эквивалентно следующему:
(u)-[]->()-[]->()-[]->(v) and (u)-[]->()-[]->()-[]->()-[]->(v) and (u)-[]->()-[]->()-[]->()-[]->()-[]->(v)
В приведённом выше примере для пути задавалась как нижняя, так и верхняя граница количества рёбер (и вершин) между u
и v
. Можно исключить одно или оба эти значения связывания.
(u)-[*3..]->(v)
Возвращает все пути между u
и v
, включающие три или более рёбер.
(u)-[*..5]->(v)
Возвращает все пути между u
и v
, включающие пять или менее рёбер.
(u)-[*]->(v)
Возвращает все пути между u
и v
.
H.1.9.3.1. Пример #
SELECT * FROM cypher('graph_name', $$ MATCH p = (actor {name: 'Willam Dafoe'})-[:ACTED_IN*2]-(co_actor) RETURN relationships(p) $$) as (r agtype); r ------------------------------------------------------------------------------------------------------------------------------------------------------------------ [{id: 0; label:"ACTED_IN"; properties: {role: "Green Goblin"}}::edge, {id: 1; label: "ACTED_IN; properties: {role: "Spiderman", actor: "Toby Maguire}}::edge] [{id: 0; label:"ACTED_IN"; properties: {role: "Green Goblin"}}::edge, {id: 2; label: "ACTED_IN; properties: {role: "Spiderman", actor: "Andrew Garfield"}}::edge] (2 rows)
Возвращает список рёбер, относящихся к ролям «Willam Dafoe» и актёрам, с которыми он работал.
H.1.10. WITH #
Используя WITH
, можно работать с выводом, прежде чем он будет передан в следующие части запроса. Например, можно изменять форму и/или количество записей в наборе результатов.
В WITH
и RETURN
можно задавать псевдонимы выражений, используемые в качестве имени связывания.
WITH
также используется, чтобы отделить чтение графа от его изменения. Каждая часть запроса должна быть доступна либо только для чтения, либо только для записи. При переходе от части записи к части чтения переключение можно выполнить с помощью необязательного предложения WITH
.
H.1.10.1. Фильтр результатов агрегатной функции #
Чтобы можно было фильтровать агрегированные результаты, они должны пройти через предложение WITH
.
SELECT * FROM cypher('graph_name', $$ MATCH (david {name: 'David'})-[]-(otherPerson)-[]->() WITH otherPerson, count(*) AS foaf WHERE foaf > 1 RETURN otherPerson.name $$) as (name agtype); name -------- "Anders" (1 row)
Запрос вернёт имя человека, связанного с «David» более чем одним исходящим отношением.
H.1.10.2. Сортировка результатов перед использованием функции collect
#
Можно отсортировать результаты перед их передачей в collect
, таким образом получившийся список тоже будет отсортирован.
SELECT * FROM cypher('graph_name', $$ MATCH (n)WITH n ORDER BY n.name DESC LIMIT 3 RETURN collect(n.name) $$) as (names agtype); names ------------------------- ["Emil","David","Ceasar"] (1 row)
Возвращается список из не более чем трёх имён людей в обратном порядке.
H.1.10.3. Ограничение ветвления поиска пути #
Можно сопоставить пути, ограничить их количество, а затем снова сопоставить, используя в качестве основы эти пути, а также любое количество подобных ограниченных поисков.
SELECT * FROM cypher('graph_name', $$ MATCH (n {name: 'Anders'})-[]-(m)WITH m ORDER BY m.name DESC LIMIT 1 MATCH (m)-[]-(o) RETURN o.name $$) as (name agtype); name ------- "Anders" "Bossman" (2 rows)
Начиная с «Anders», находит все совпадающие узлы, упорядочивает их в алфавитном порядке и получает верхний результат, затем находит все узлы, связанные с этим верхним результатом, и возвращает их имена.
H.1.11. RETURN #
В части RETURN
запроса определяется, какие части шаблона представляют интерес. Это могут быть узлы, связи или свойства в них.
H.1.11.1. Вывод узлов #
Чтобы вернуть узел, укажите его в операторе RETURN
.
SELECT * FROM cypher('graph_name', $$ MATCH (n {name: 'B'}) RETURN n $$) as (n agtype); n --------------------------------------------------- {id: 0; label: '' properties: {name: 'B'}}::vertex (1 row)
В примере возвращается узел.
H.1.11.2. Вывод рёбер #
Чтобы вернуть n
рёбер, просто включите их в список RETURN
.
SELECT * FROM cypher('graph_name', $$ MATCH (n)-[r:KNOWS]->() WHERE n.name = 'A' RETURN r $$) as (r agtype); r ------------------------------------------------------------------- {id: 2; startid: 0; endid: 1; label: 'KNOWS' properties: {}}::edge (1 row)
В примере возвращается отношение.
H.1.11.3. Получение свойств #
Чтобы вернуть свойство, используйте разделитель-точку, например:
SELECT * FROM cypher('graph_name', $$ MATCH (n {name: 'A'}) RETURN n.name $$) as (name agtype); name ------ 'A' (1 row)
Возвращается значение name
свойства.
H.1.11.4. Получение всех элементов #
Если необходимо вернуть все вершины, рёбра и пути, соответствующие запросу, можно использовать символ *
.
SELECT * FROM cypher('graph_name', $$ MATCH (a {name: 'A'})-[r]->(b) RETURN * $$) as (a agtype, b agtype, r agtype); a | b | r --------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------- {"id": 281474976710659, "label": "", "properties": {"age": 55, "name": "A", "happy": "Yes!"}}::vertex | {"id": 1125899906842625, "label": "BLOCKS", "end_id": 281474976710660, "start_id": 281474976710659, "properties": {}}::edge | {"id": 281474976710660, "label": "", "properties": {"name": "B"}}::vertex {"id": 281474976710659, "label": "", "properties": {"age": 55, "name": "A", "happy": "Yes!"}}::vertex | {"id": 1407374883553281, "label": "KNOWS", "end_id": 281474976710660, "start_id": 281474976710659, "properties": {}}::edge | {"id": 281474976710660, "label": "", "properties": {"name": "B"}}::vertex (2 rows)
Возвращает две вершины и ребро, указанные в запросе.
H.1.11.5. Переменные с необычными символами #
Чтобы ввести заполнитель, состоящий из символов, которых нет в английском алфавите, переменную можно заключить в `
, например:
SELECT * FROM cypher('graph_name', $$ MATCH (`This isn\'t a common variable`) WHERE `This isn\'t a common variable`.name = 'A' RETURN `This isn\'t a common variable`.happy $$) as (happy agtype); happy ------- "Yes!" (1 row)
Возвращается узел с именем «A».
H.1.11.6. Псевдоним поля #
Если имя поля должно отличаться от используемого выражения, можно переименовать его, изменив имя в определении списка столбцов.
SELECT * FROM cypher('graph_name', $$ MATCH (n {name: 'A'}) RETURN n.name $$) as (objects_name agtype); objects_name ------------- 'A' (1 row)
Возвращает свойство узла, но переименовывает поле.
H.1.11.7. Необязательные свойства #
Если неизвестно, существует ли свойство, к нему всё равно можно обратиться как обычно. Если оно отсутствует, будет считаться, что оно имеет значение null
.
SELECT * FROM cypher('graph_name', $$ MATCH (n) RETURN n.age $$) as (age agtype); age ----- 55 NULL (2 rows)
В этом примере возвращается свойство age
, если оно есть у узла, или значение null
, если его нет.
H.1.11.8. Прочие выражения #
В качестве возвращаемого элемента можно использовать любое выражение — литералы, предикаты, свойства, функции и всё прочее.
SELECT * FROM cypher('graph_name', $$ MATCH (a) RETURN a.age > 30, 'I\'m a literal', id(a) $$) as (older_than_30 agtype, literal agtype, id agtype); older_than_30 | literal | id ---------------+-----------------+---- true | 'I'm a literal' | 1 (1 row)
Возвращает предикат, литерал и вызов функции с параметром выражения шаблона.
H.1.11.9. Уникальные результаты #
DISTINCT
извлекает только уникальные записи в зависимости от полей, выбранных для вывода.
SELECT * FROM cypher('graph_name', $$ MATCH (a {name: 'A'})-[]->(b) RETURN DISTINCT b $$) as (b agtype); b ---------------------------------------------------- {id: 1; label: '' properties: {name: 'B'}}::vertex (1 row)
Запрос возвращает узел с именем «B», но только один раз.
H.1.12. ORDER BY #
ORDER BY
— это вложенное предложение, следующее за WITH
и указывающее, что вывод должен быть отсортирован и как именно.
Обратите внимание, что можно сортировать только свойства узлов и отношений, но не сами узлы или отношения. В ORDER BY
используется сравнение для сортировки вывода, за дополнительной информацией обратитесь к описанию упорядочивания и сравнения значений.
В зависимости от того, является ли проецируемое предложение RETURN
или WITH
агрегирующим или DISTINCT
, действуют различные правила доступности переменных. Если эта проекция агрегирующая или DISTINCT
, доступны только переменные, доступные в проекции. Если проекция не меняет количество результатов (в отличие от агрегирования и DISTINCT
), доступны также переменные, указанные до предложения проецирования. Если проецируемое предложение скрывает уже существующие переменные, доступны только новые переменные.
Не разрешается использовать агрегатные выражения во вложенном предложении ORDER BY
, если они также не перечислены в проецируемом предложении. Последнее правило предназначено для того, чтобы убедиться, что ORDER BY
изменяет не результаты, а только их порядок.
H.1.12.1. Упорядочивание узлов по свойству #
ORDER BY
используется для сортировки вывода.
SELECT * FROM cypher('graph_name', $$ MATCH (n) WITH n.name as name, n.age as age ORDER BY n.name RETURN name, age $$) as (name agtype, age agtype); name | age --------+----- "A" | 34 "B" | 34 "C" | 32 (3 rows)
Возвращаются узлы, отсортированные по имени.
H.1.12.2. Упорядочивание узлов по нескольким свойствам #
Можно упорядочить значения по нескольким свойствам, указав каждую переменную в предложении ORDER BY
. Cypher отсортирует результаты по первой указанной переменной и, если значения равны, перейдёт к следующему свойству в предложении ORDER BY
и так далее.
SELECT * FROM cypher('graph_name', $$ MATCH (n) WITH n.name as name, n.age as age ORDER BY n.age, n.name RETURN name, age $$) as (name agtype, age agtype); name | age --------+----- "C" | 32 "A" | 34 "B" | 34 (3 rows)
Возвращает узлы, отсортированные сначала по свойству возраста, а затем по имени.
H.1.12.3. Упорядочивание узлов в порядке убывания #
Если добавить DESC[ENDING]
после переменной для сортировки, сортировка будет выполнена в обратном порядке.
SELECT * FROM cypher('graph_name', $$ MATCH (n) WITH n.name AS name, n.age AS age ORDER BY n.name DESC RETURN name, age $$) as (name agtype, age agtype); name | age --------+----- "C" | 32 "B" | 34 "A" | 34 (3 rows)
В примере возвращаются узлы, отсортированные по имени в обратном порядке.
H.1.12.4. Упорядочивание null #
При сортировке набора результатов значение null
всегда будет находиться в конце набора результатов при сортировке по возрастанию и в начале при сортировке по убыванию.
SELECT * FROM cypher('graph_name', $$ MATCH (n) WITH n.name AS name, n.age AS age, n.height AS height ORDER BY n.height RETURN name, age, height $$) as (name agtype, age agtype, height agtype); name | age | height --------+-----+-------- "A" | 34 | 170 "C" | 32 | 185 "B" | 34 | NULL (3 rows)
Узлы возвращаются отсортированными по свойству длины, причём последним является узел без этого свойства.
H.1.13. SKIP #
SKIP
определяет, с какой записи начинать включение записей в вывод.
При использовании SKIP
набор результатов будет усечён сверху. Обратите внимание, что порядок вывода результата — произвольный, если в запросе не указано предложение ORDER BY
. SKIP
принимает любое выражение, результатом которого является положительное целое число.
H.1.13.1. Пропуск первых трёх строк #
Чтобы вернуть подмножество строк из результата, начиная сверху, используйте следующий синтаксис:
SELECT * FROM cypher('graph_name', $$ MATCH (n) RETURN n.name ORDER BY n.name SKIP 3 $$) as (names agtype); names ------- "D" "E" (2 rows)
Возвращается узел, и для него не существует свойство age
.
H.1.13.2. Получение двух средних строк #
Чтобы вернуть подмножество строк из результата, начиная с середины, используйте следующий синтаксис:
SELECT * FROM cypher('graph_name', $$ MATCH (n) RETURN n.name ORDER BY n.name SKIP 1 LIMIT 2 $$) as (names agtype); names ------- "B" "C" (2 rows)
Возвращаются две вершины из середины.
H.1.13.3. Использование выражения с SKIP для возвращения подмножества строк #
Использование выражения с SKIP
для возвращения подмножества строк.
SELECT * FROM cypher('graph_name', $$ MATCH (n) RETURN n.name ORDER BY n.name SKIP (3 * rand())+ 1 $$) as (a agtype); names ------- "C" "D" "E" (3 rows)
Первые две вершины пропускаются, и в результате возвращаются только последние три.
H.1.14. LIMIT #
LIMIT
ограничивает количество записей в выводе.
LIMIT
принимает любое выражение, результатом которого является положительное целое число.
H.1.14.1. Получение подмножества строк #
Чтобы вернуть подмножество строк из результата, начиная сверху, используйте следующий синтаксис:
SELECT * FROM cypher('graph_name', $$ MATCH (n)RETURN n.name ORDER BY n.name LIMIT 3 $$) as (names agtype); names "A" "B" "C" 3 rows
Возвращается узел, и для него не существует свойство age
.
H.1.14.2. Использование выражения с LIMIT для возвращения подмножества строк #
LIMIT
принимает любое выражение, результатом которого является положительное целое число, если это выражение не ссылается на какие-либо внешние переменные:
SELECT * FROM cypher('graph_name', $$ MATCH (n) RETURN n.name ORDER BY n.name LIMIT toInteger(3 * rand()) + 1 $$) as (names agtype); names ------- "A" "B" (2 rows)
Возвращает от одного до трёх верхних элементов.
H.1.15. CREATE #
Предложение CREATE
используется для создания вершин и рёбер графа.
H.1.15.1. Завершающее предложение CREATE #
Предложение CREATE
, за которым не следует другое предложение, называется завершающим предложением. Когда Cypher-запрос заканчивается завершающим предложением, результаты вызова функции Cypher не возвращаются. Однако вызов Cypher-функции по-прежнему требует определения списка столбцов. Когда Cypher-запрос заканчивается завершающим узлом, задайте одно значение в определении списка столбцов: в этой переменной не будут возвращаться данные.
SELECT * FROM cypher('graph_name', $$ CREATE /* Create clause here, no following clause */ $$) as (a agtype); a --- (0 rows)
H.1.15.2. Создание одной вершины #
Создать одну вершину можно с помощью следующего запроса.
SELECT * FROM cypher('graph_name', $$ CREATE (n) $$) as (v agtype); v --- (0 rows)
Этот запрос ничего не возвращает.
H.1.15.3. Создание нескольких вершин #
Можно создать нескольких вершин, разделив их запятыми.
SELECT * FROM cypher('graph_name', $$ CREATE (n), (m) $$) as (v agtype); a ------- (0 rows)
H.1.15.4. Создание вершины с меткой #
Для добавления метки при создании вершины используйте следующий синтаксис.
SELECT * FROM cypher('graph_name', $$ CREATE (:Person) $$) as (v agtype); v ------- (0 rows)
Этот запрос ничего не возвращает.
H.1.15.5. Создание вершины и добавление меток и свойств #
При создании новой вершины с метками можно сразу добавить свойства.
SELECT * FROM cypher('graph_name', $$ CREATE (:Person {name: 'Andres', title: 'Developer'}) $$) as (n agtype); n ------- (0 rows)
Этот запрос ничего не возвращает.
H.1.15.6. Получение созданного узла #
Создать один узел можно с помощью следующего запроса.
SELECT * FROM cypher('graph_name', $$ CREATE (a {name: 'Andres'}) RETURN a $$) as (a agtype); a -------------------------------------------------------------------------------- {"id": 281474976710660, "label": "", "properties": {"name": "Andres"}}::vertex (1 row)
Возвращается только что созданный узел.
H.1.15.7. Создание ребра между двумя узлами #
Чтобы создать ребро между двумя вершинами, сначала нужно получить две вершины. После загрузки узлов просто создайте между ними ребро.
SELECT * FROM cypher('graph_name', $$ MATCH (a:Person), (b:Person) WHERE a.name = 'Node A' AND b.name = 'Node B' CREATE (a)-[e:RELTYPE]->(b) RETURN e $$) as (e agtype); e ----------------------------------------------------------------------- {id: 3; startid: 0, endid: 1; label: 'RELTYPE'; properties: {}}::edge (1 row)
Запрос возвращает созданное ребро.
H.1.15.8. Создание ребра и установка свойств #
Свойства рёбер устанавливаются так же, как при создании вершин. Обратите внимание, что значения могут быть любым выражением.
SELECT * FROM cypher('graph_name', $$ MATCH (a:Person), (b:Person) WHERE a.name = 'Node A' AND b.name = 'Node B' CREATE (a)-[e:RELTYPE {name:a.name + '<->' + b.name}]->(b) RETURN e $$) as (e agtype); e --------------------------------------------------------------------------------------------------- {id: 3; startid: 0, endid: 1; label: 'RELTYPE'; properties: {name: 'Node A<->Node B'}}::edge (1 row)
Запрос в примере возвращает только что созданное ребро.
H.1.15.9. Создание полного пути #
При использовании CREATE
и шаблона будут созданы все части шаблона, которые ещё не находятся в области видимости.
SELECT * FROM cypher('graph_name', $$ CREATE p = (andres {name:'Andres'})-[:WORKS_AT]->(neo)<-[:WORKS_AT]-(michael {name:'Michael'}) RETURN p $$) as (p agtype); p ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [{"id": 281474976710661, "label": "", "properties": {"name": "Andres"}}::vertex, {"id": 1407374883553282, "label": "WORKS_AT", "end_id": 281474976710662, "start_id": 281474976710661, "properties": {}}::edge, {"id": 281474976710662, "label": "", "properties": {}}::vertex, {"id": 1407374883553281, "label": "WORKS_AT", "end_id": 281474976710662, "start_id": 281474976710663, "properties": {}}::edge, {"id": 281474976710663, "label": "", "properties": {"name": "Michael"}}::vertex]::path (1 row)
Этот запрос создаёт сразу три узла и два отношения, назначает их переменной пути и возвращает её.
H.1.16. DELETE #
Предложение DELETE
используется для удаления элементов графа — узлов, связей или путей.
Предложение DELETE
, за которым не следует другое предложение, называется завершающим предложением. Когда Cypher-запрос заканчивается завершающим предложением, результаты вызова функции Cypher не возвращаются. Однако вызов Cypher-функции по-прежнему требует определения списка столбцов. Когда Cypher-запрос заканчивается завершающим узлом, задайте одно значение в определении списка столбцов: в этой переменной не будут возвращаться данные.
Подробное описание удаления свойств находится в Подразделе H.1.17.4.
Можно удалить узел, не удаляя рёбра, которые начинаются или заканчиваются в указанной вершине. Либо удалите вершины явно, либо используйте DETACH DELETE
.
H.1.16.1. Удаление изолированных вершин #
Для удаления вершины используйте предложение DELETE
.
SELECT * FROM cypher('graph_name', $$ MATCH (v:Useless) DELETE v $$) as (v agtype); v ------- (0 rows)
В результате такого запроса удалятся вершины (с меткой «Useless»), у которых нет рёбер. Этот запрос ничего не возвращает.
H.1.16.2. Удаление всех вершин и связанных с ними рёбер #
В результате запроса с предложением MATCH
собираются все узлы. Используйте параметр DETACH
, чтобы сначала удалить рёбра вершины, а затем удалить саму вершину.
SELECT * FROM cypher('graph_name', $$ MATCH (v:Useless) DETACH DELETE v $$) as (v agtype); v ------- (0 rows)
Этот запрос ничего не возвращает.
H.1.16.3. Удаление только рёбер #
Чтобы удалить ребро, используйте предложение MATCH
для поиска нужных рёбер, а затем добавьте переменную в DELETE
.
SELECT * FROM cypher('graph_name', $$ MATCH (n {name: 'Andres'})-[r:KNOWS]->() DELETE r $$) as (v agtype); v ------- (0 rows)
Этот запрос ничего не возвращает.
H.1.16.4. Получение удалённой вершины #
В apache_age можно вывести удалённые вершины.
SELECT * FROM cypher('graph_name', $$ MATCH (n {name: 'A'}) DELETE n RETURN n $$) as (a agtype); a --------------------------------------------------------------------------- {"id": 281474976710659, "label": "", "properties": {"name": "A"}}::vertex (1 rows)
H.1.17. SET #
Предложение SET
используется для изменения меток узлов и свойств вершин и рёбер.
H.1.17.1. Завершающие предложения SET #
Предложение SET
, за которым не следует другое предложение, называется завершающим предложением. Когда Cypher-запрос заканчивается завершающим предложением, результаты вызова функции Cypher не возвращаются. Однако вызов Cypher-функции по-прежнему требует определения списка столбцов. Когда Cypher-запрос заканчивается завершающим узлом, задайте одно значение в определении списка столбцов: в этой переменной не будут возвращаться данные.
H.1.17.2. Установка свойства #
Чтобы установить свойство узла или отношения, используйте SET
.
SELECT * FROM cypher('graph_name', $$ MATCH (v {name: 'Andres'}) SET v.surname = 'Taylor' $$) as (v agtype); v ------- (0 rows)
Запрос возвращает только что изменённый узел.
H.1.17.3. Получение созданной вершины #
Создать одну вершину можно с помощью следующего запроса.
SELECT * FROM cypher('graph_name', $$ MATCH (v {name: 'Andres'}) SET v.surname = 'Taylor' RETURN v $$) as (v agtype); v ----------------------------------------------------------------------------------------------------- {id: 3; label: 'Person'; properties: {surname:"Taylor", name:"Andres", age:36, hungry:true}}::vertex (1 row)
Запрос возвращает только что изменённую вершину.
H.1.17.4. Удаление свойства #
Обычно свойство удаляется с помощью команды REMOVE
, но иногда бывает удобно сделать это с помощью команды SET
. Одним из примеров является ситуация, когда свойство получено из параметра.
SELECT * FROM cypher('graph_name', $$ MATCH (v {name: 'Andres'}) SET v.name = NULL RETURN v $$) as (v agtype); v --------------------------------------------------------------------------------------- {id: 3; label: 'Person'; properties: {surname:"Taylor", age:36, hungry:true}}::vertex (1 row)
Запрос возвращает узел, и свойство name теперь отсутствует.
H.1.17.5. Задание нескольких свойств в одном предложении SET #
Если нужно задать несколько свойств сразу, разделите их запятыми.
SELECT * FROM cypher('graph_name', $$ MATCH (v {name: 'Andres'}) SET v.position = 'Developer', v.surname = 'Taylor' RETURN v $$) as (v agtype); v ------------------------------------------------------------------------------------------------------------------------------ {"id": 281474976710661, "label": "", "properties": {"name": "Andres", "surname": "Taylor", "position": "Developer"}}: :vertex (1 row)
H.1.18. REMOVE #
Предложение REMOVE
используется для удаления свойств вершин и рёбер.
Предложение REMOVE
, за которым не следует другое предложение, называется завершающим предложением. Когда Cypher-запрос заканчивается завершающим предложением, результаты вызова функции Cypher не возвращаются. Однако вызов Cypher-функции по-прежнему требует определения списка столбцов. Когда Cypher-запрос заканчивается завершающим узлом, задайте одно значение в определении списка столбцов: в этой переменной не будут возвращаться данные.
В Cypher запрещается хранить null
в свойствах. Если значение не существует, свойство отсутствует. Таким образом, удаление значения свойства узла или отношения также выполняется с помощью REMOVE
.
SELECT * FROM cypher('graph_name', $$ MATCH (andres {name: 'Andres'}) REMOVE andres.age RETURN andres $$) as (andres agtype); andres --------------------------------------------------------------- {id: 3; label: 'Person'; properties: {name:"Andres"}}::vertex (1 row)
Возвращается узел, и для него не существует свойство age
.
H.1.19. MERGE #
Предложение MERGE
гарантирует наличие шаблона в графе. Шаблон либо уже существует, либо его необходимо создать.
MERGE
либо сопоставляет существующие узлы, либо создаёт новые данные. Это сочетание предложений MATCH
и CREATE
.
Например, можно указать, что граф должен содержать узел для пользователя с определённым именем. Если узла с таким именем нет, будет создан новый узел с заданным свойством имени. При использовании MERGE
для полных шаблонов либо должен совпадать весь шаблон, либо создаётся новый шаблон. MERGE
не использует существующие шаблоны частично. Если необходимо использовать частичные совпадения, это можно сделать, разбив шаблон на несколько предложений MERGE
.
Как и в случае с MATCH
, MERGE
может сопоставлять несколько вхождений шаблона. Если совпадений несколько, все они будут переданы на более поздние этапы запроса.
SELECT * from cypher('graph_name', $$ CREATE (A:Person {name: 'Charlie Sheen', bornIn: 'New York'}), (B:Person {name: 'Michael Douglas', bornIn: 'New Jersey'}), (C:Person {name: 'Rob Reiner', bornIn: 'New York'}), (D:Person {name: 'Oliver Stone', bornIn: 'New York'}), (E:Person {name: 'Martin Sheen', bornIn: 'Ohio'}) $$) as (result agtype);
H.1.19.1. MERGE для узлов #
H.1.19.1.1. MERGE для узлов с меткой #
Если указать шаблон с одной вершиной и без меток, будут возвращены все вершины графа.
SELECT * FROM cypher('graph_name', $$ MERGE (v:Critic) RETURN v $$) as (v agtype); v ------------------------------------------------- {id: 0; label: 'Critic': properties:{}}::vertex (1 row)
Если существует вершина с меткой «Critic», возвращается вершина. В противном случае вершина сначала создаётся, а затем возвращается.
H.1.19.1.2. MERGE для одной вершины со свойствами #
Выполнение команды MERGE для узла вершины со свойствами, не все из которых соответствуют какой-либо существующей вершине.
SELECT * FROM cypher('graph_name', $$ MERGE (charlie {name: 'Charlie Sheen', age: 10}) RETURN charlie $$) as (v agtype); v ------------------------------------------------------------------------------ {id: 0; label: 'Actor': properties:{name: 'Charlie Sheen', age: 10}}::vertex (1 row)
Если существует вершина с меткой «Critic», возвращается вершина. В противном случае вершина сначала создаётся, а затем возвращается.
Если вершина со всеми свойствами существует, она будет возвращена. В противном случае будет создана и возвращена новая вершина с именем «Charlie Sheen».
H.1.19.1.3. MERGE для одной вершины с указанием как метки, так и свойств #
Объединение вершины, в которой ограничения метки и свойства соответствуют существующей вершине.
SELECT * FROM cypher('graph_name', $$ MERGE (michael:Person {name: 'Michael Douglas'}) RETURN michael.name, michael.bornIn $$) as (Name agtype, BornIn agtype); name | bornin -------------------+-------------- "Michael Douglas" | "New Jersey" (1 row)
«Michael Douglas» совпадает с существующей вершиной, и возвращаются свойства name
и bornIn
этой вершины.
H.1.20. Функции-предикаты #
Предикаты — это логические функции, которые возвращают true или false для заданного набора входных данных. Чаще всего они используются для фильтрации подграфов в части WHERE
запроса.
-
exists(
#property
agtype
) returns agtype boolean Функция
exists()
возвращаетtrue
, если указанное свойство существует в узле, отношении или ассоциативном массиве. Её действие отличается от действия предложенияEXISTS
.SELECT * FROM cypher('graph_name', $$ MATCH (n) WHERE exists(n.surname) RETURN n.first_name, n.last_name $$) as (first_name agtype, last_name agtype); first_name | last_name ------------+------------ 'John' | 'Smith' 'Patty' | 'Patterson' (2 rows)
-
exists(
#path
agtype
) returns agtype boolean Функция
exists()
возвращаетtrue
, если заданный путь уже существует.SELECT * FROM cypher('graph_name', $$ MATCH (n) WHERE exists((n)-[]-({name: 'Willem Defoe'})) RETURN n.full_name $$) as (full_name agtype); full_name -------------- 'Toby Maguire' 'Tom Holland' (2 rows)
H.1.21. Скалярные функции #
-
id(
#expression
agtype
) returns agtype integer Функция
id()
возвращает идентификатор вершины или ребра.SELECT * FROM cypher('graph_name', $$ MATCH (a) RETURN id(a) $$) as (id agtype); id ---- 0 1 2 3 (4 rows)
-
start_id(
#expression
agtype
) returns agtype integer Функция
start_id()
возвращает идентификатор начальной вершины ребра.SELECT * FROM cypher('graph_name', $$ MATCH ()-[e]->() RETURN start_id(e) $$) as (start_id agtype); start_id ---------- 0 1 2 3 (4 rows)
-
end_id(
#expression
agtype
) returns agtype integer Функция
end_id()
возвращает идентификатор конечной вершины ребра.SELECT * FROM cypher('graph_name', $$ MATCH ()-[e]->() RETURN end_id(e) $$) as (end_id agtype); end_id -------- 4 5 6 7 (4 rows)
-
type(
#edge
agtype
) returns agtype string Функция
type()
возвращает тип ребра в виде строки.SELECT * FROM cypher('graph_name', $$ MATCH ()-[e]->() RETURN type(e) $$) as (type agtype); type ------ 'KNOWS' 'KNOWS' (2 rows)
-
properties(
#expression
agtype
) returns agtype map Функция
properties()
возвращает значение типа agtype map, содержащее все свойства вершины или ребра. Если аргумент уже является ассоциативным массивом, он возвращается без изменений. Функцияproperties(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ CREATE (p:Person {name: 'Stefan', city: 'Berlin'}) RETURN properties(p) $$) as (type agtype); type -------------------------------------- {"city": "Berlin", "name": "Stefan"} (1 row)
-
head(
#list
agtype
) returns agtype Функция
head()
возвращает первый элемент в списке типов. Функцияhead(null)
возвращаетnull
. Если первый элемент в списке —null
, функцияhead(list)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ MATCH (a) WHERE a.name = 'Eskil' RETURN a.array, head(a.array) $$) as (lst agtype, lst_head agtype); lst | lst_head -----------------------+---------- ["one","two","three"] | "one" (1 row)
-
last(
#list
agtype
) returns agtype Функция
last()
возвращает последний элемент в значении типа agtype list. Функцияlast(null)
возвращаетnull
. Если последний элемент в списке —null
, функцияlast(list)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ MATCH (a) WHERE a.name = 'Eskil' RETURN a.array, last(a.array) $$) as (lst agtype, lst_tail agtype); lst | lst_tail -----------------------+---------- ["one","two","three"] | "three" (1 row)
-
length(
#path
agtype
) returns agtype integer Функция
length()
возвращает длину пути. Функцияlength(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ MATCH p = (a)-[]->(b)-[]->(c) WHERE a.name = 'Alice' RETURN length(p) $$) as (length_of_path agtype); length_of_path ---------------- 2 2 2 (3 rows)
-
size(
#list
variadic "any"
) returns agtype integer Функция
size()
возвращает длину списка. Функцияsize(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN size(['Alice', 'Bob']) $$) as (size_of_list agtype); size_of_list -------------- 2 (1 row)
-
startNode(
#edge
agtype
) returns agtype Функция
startNode()
возвращает начальный узел ребра. ФункцияstartNode(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ MATCH (x:Developer)-[r]-() RETURN startNode(r) $$) as (v agtype); v ------------------------------------------ Node[0]{name:"Alice",age:38,eyes:"brown"} Node[0]{name:"Alice",age:38,eyes:"brown"} (2 rows)
-
endNode(
#edge
agtype
) returns agtype Функция
endNode()
возвращает конечный узел ребра. ФункцияendNode(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ MATCH (x:Developer)-[r]-() RETURN endNode(r) $$) as (v agtype); v ------------------------------------------- Node[2]{name:"Charlie",age:53,eyes:"green"} Node[1]{name:"Bob",age:25,eyes:"blue"} (2 rows)
-
timestamp() returns agtype integer
# Функция
timestamp()
возвращает разницу в миллисекундах между текущим временем и полуночью 1 января 1970 года по UTC. Функцияtimestamp
возвращает одно и то же значение в течение всего запроса, даже для длительных запросов.SELECT * FROM cypher('graph_name', $$ RETURN timestamp() $$) as (t agtype); t --------------- 1613496720760 (1 row)
-
toBoolean(
#expression
variadic "any"
) returns agtype boolean Функция
toBoolean()
преобразует строковое значение в логическое значение. ФункцияtoBoolean(null)
возвращаетnull
. Если выражение является логическим значением, оно возвращается без изменений. Если разбор завершается ошибкой, возвращаетсяnull
.SELECT * FROM cypher('graph_name', $$ RETURN toBoolean('TRUE'), toBoolean('not a boolean') $$) as (a_bool agtype, not_a_bool agtype); a_bool | not_a_bool --------+------------ true | NULL (1 row)
-
toFloat(
#expression
variadic "any"
) returns agtype float Функция
toFloat()
преобразует целое число или строковое значение в число с плавающей точкой. ФункцияtoFloat(null)
возвращаетnull
. Если выражение представляет собой число с плавающей точкой, оно возвращается без изменений. Если разбор завершается ошибкой, возвращаетсяnull
.SELECT * FROM cypher('graph_name', $$ RETURN toFloat('11.5'), toFloat('not a number') $$) as (a_float agtype, not_a_float agtype); a_float | not_a_float ---------+------------- 11.5 | NULL (1 row)
-
toInteger(
#expression
variadic "any"
) returns agtype integer Функция
toInteger()
преобразует число с плавающей точкой или строковое значение в целочисленное значение.toInteger(null)
возвращаетnull
. Если выражение является целочисленным значением, оно возвращается без изменений. Если разбор завершается ошибкой, возвращаетсяnull
.SELECT * FROM cypher('graph_name', $$ RETURN toInteger('42'), toInteger('not a number') $$) as (an_integer agtype, not_an_integer agtype); an_integer | not_an_integer ------------+---------------- 42 | NULL (1 row)
-
coalesce(
#expression
agtype
[,expression
agtype
]*) returns agtype Функция
coalesce()
возвращает первое значение, не являющееся null, из заданного списка выражений. Если все аргументы имеют значениеnull
, возвращается значениеnull
.SELECT * FROM cypher('graph_name', $$ MATCH (a) WHERE a.name = 'Alice' RETURN coalesce(a.hairColor, a.eyes), a.hair_color, a.eyes $$) as (color agtype, hair_color agtype, eyes agtype); color | hair_color | eyes -------+------------+-------- “brown”| NULL | “Brown” (1 row)
H.1.22. Функции списка #
SELECT * from cypher('graph_name', $$ CREATE (A:Person {name: 'Alice', age: 38, eyes: 'brown'}), (B:Person {name: 'Bob', age: 25, eyes: 'blue'}), (C:Person {name: 'Charlie', age: 53, eyes: 'green'}), (D:Person {name: 'Daniel', age: 54, eyes: 'brown'}), (E:Person {name: 'Eskil', age: 41, eyes: 'blue', array: ['one', 'two', 'three']}), (A)-[:KNOWS]->(B), (A)-[:KNOWS]->(C), (B)-[:KNOWS]->(D), (C)-[:KNOWS]->(D), (B)-[:KNOWS]->(E) $$) as (result agtype);
-
keys(
#expression
agtype
) returns agtype list Функция
keys()
возвращает список, содержащий строковые представления всех имён свойств вершины, ребра или ассоциативного массива. Функцияkeys(null)
возвращаетnull
.SELECT * from cypher('graph_name', $$ MATCH (a) WHERE a.name = 'Alice' RETURN keys(a) $$) as (result agtype); result ------------------------- ["age", "eyes", "name"] (1 row)
Возвращается список, содержащий имена всех свойств вершины, привязанной к
a
.-
range(
#start
variadic "any"
,end
variadic "any"
[,step
variadic "any"
]) returns agtype list Функция
range()
возвращает список, содержащий все целочисленные значения в диапазоне, который ограничен начальным значениемstart
и конечным значениемend
, где разностьstep
между любыми двумя последовательными значениями является постоянной. То есть возвращаемый список является арифметической прогрессией. Диапазон является инклюзивным, поэтому арифметическая прогрессия всегда будет содержатьstart
и — в зависимости от значенийstart
,step
иend
—end
.SELECT * FROM cypher('graph_name', $$ RETURN range(0, 10), range(2, 18, 3) $$) as (no_step agtype, step agtype); no_step | step ------------------------------------+----------------------- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] | [2, 5, 8, 11, 14, 17] (1 row)
Возвращаются два списка чисел в заданных диапазонах.
-
labels(
#vertex
agtype
) returns agtype list Функция
labels()
возвращает список, содержащий строковые представления всех меток узла. Функцияlabels(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ MATCH (a) WHERE a.name = 'Alice' RETURN labels(a) $$) as (edges agtype); edges ------------ ["Person"] (1 row)
Возвращается список, содержащий все метки узла, привязанного к
a
.-
nodes(
#path
agtype
) returns agtype list Функция
nodes()
возвращает список, содержащий все вершины пути. Функцияnodes(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ MATCH p = (a)-[]->(b)-[]->(c) WHERE a.name = 'Alice' AND c.name = 'Eskil' RETURN nodes(p) $$) as (vertices agtype); vertices ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [{"id": 844424930131969, "label": "Person", "properties": {"age": 38, "eyes": "brown", "name": "Alice"}}::vertex, {"id": 844424930131970, "label": "Person", "properties": {"age": 25, "eyes": "blue", "name": "Bob"}}::vertex, {"id": 844424930131973, "label": "Person", "properties": {"age": 41, "eyes": "blue", "name": "Eskil", "array": ["one", "two", "three"]}}::vertex] (1 row)
Возвращается список, содержащий все вершины пути
p
.-
relationships(
#path
agtype
) returns agtype list Функция
relationships()
возвращает список, содержащий все отношения пути. Функцияrelationships(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ MATCH p = (a)-[]->(b)-[]->(c) WHERE a.name = 'Alice' AND c.name = 'Eskil' RETURN relationships(p) $$) as (edges agtype); edges ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [{"id": 1125899906842625, "label": "KNOWS", "end_id": 844424930131970, "start_id": 844424930131969, "properties": {}}::edge, {"id": 1125899906842629, "label": "KNOWS", "end_id": 844424930131973, "start_id": 844424930131970, "properties": {}}::edge] (1 row)
Возвращается список, содержащий все рёбра пути
p
.-
toBooleanList(
#list
variadic "any"
) returns agtype list Функция
toBooleanList()
преобразует список значений в список логических значений. Если какие-либо значения не могут быть преобразованы в логические значения, в возвращаемом списке они будут иметь значениеnull
. Значенияnull
и логические значения в списке сохраняются. Если список имеет значениеnull
, возвращаетсяnull
.SELECT * FROM cypher('expr', $$ RETURN toBooleanList(['true', 'false', 'true']) $$) AS (toBooleanList agtype); toBooleanList -------------------- [true, false, true] (1 row)
H.1.23. Числовые функции #
-
rand() returns agtype float
# Функция
rand()
возвращает случайное число с плавающей точкой в диапазоне от 0 (включая) до 1 (исключая), то есть [0,1). Возвращаемые числа имеют приблизительно равномерное распределение.SELECT * FROM cypher('graph_name', $$ RETURN rand() $$) as (random_number agtype); random_number ------------------- 0.3586784748902053 (1 row)
-
abs(
#list
variadic "any"
) returns agtype Функция
abs()
возвращает абсолютное значение заданного числа. Функцияabs(null)
возвращает значениеnull
. Если выражение отрицательное, возвращается-(
(т. е. отрицательная форма выражения).выражение
)SELECT * FROM cypher('graph_name', $$ MATCH (a), (e) WHERE a.name = 'Alice' AND e.name = 'Eskil' RETURN a.age, e.age, abs(a.age - e.age) $$) as (alice_age agtype, eskil_age agtype, difference agtype); alice_age | eskil_age | difference -----------+-----------+------------ 38 | 41 | 3 (1 row)
Возвращается абсолютное значение разности значений age.
-
ceil(
#expression
variadic "any"
) returns agtype float Функция
ceil()
возвращает наименьшее число с плавающей точкой, которое больше или равно заданному числу и равно математическому целому числу. Функцияceil(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN ceil(0.1) $$) as (ceil_value agtype); ceil_value ------------ 1.0 (1 row)
Возвращается округление 0.1 в большую сторону.
-
floor(
#expression
variadic "any"
) returns agtype float Функция
floor()
возвращает наибольшее число с плавающей точкой, которое меньше или равно заданному числу и равно математическому целому числу. Функцияfloor(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN floor(0.1) $$) as (flr agtype); flr ----- 0.0 (1 row)
Возвращается целая часть 0.1.
-
round(
#expression
variadic "any"
) returns agtype float Функция
round()
возвращает значение заданного числа, округлённое до ближайшего целого числа.round(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN round(3.141592) $$) as (rounded_value agtype); rounded_value --------------- 3.0 (1 row)
-
sign(
#expression
variadic "any"
) returns agtype integer Функция
sign()
возвращает знак данного числа: 0, если число равно 0, -1 для любого отрицательного числа и 1 для любого положительного числа. Функцияsign(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN sign(-17), sign(0.1), sign(0) $$) as (negative_sign agtype, positive_sign agtype, zero_sign agtype); negative_sign | positive_sign | zero_sign ---------------+---------------+----------- -1 | 1 | 0 (1 row)
Возвращаются знаки чисел -17 и 0.1.
H.1.24. Логарифмические функции #
-
e() returns agtype float
# Функция
e()
возвращает основание натурального логарифма,e
.SELECT * FROM cypher('graph_name', $$ RETURN e() $$) as (e agtype); e ------------------- 2.718281828459045 (1 row)
-
sqrt(
#expression
variadic "any"
) returns agtype float Функция
sqrt()
возвращает квадратный корень числа.SELECT * FROM cypher('graph_name', $$ RETURN sqrt(144) $$) as (results agtype); results --------- 12.0 (1 row)
-
exp(
#expression
variadic "any"
) returns agtype float Функция
exp()
возвращаетe^n
, гдеe
— основание натурального логарифма, аn
— значение аргумента выражения. Функцияexp(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN exp(2) $$) as (e agtype); e ------------------ 7.38905609893065 (1 row)
Возвращается
e
в степени 2.-
log(
#expression
variadic "any"
) returns agtype float Функция
log()
возвращает натуральный логарифм числа. Функцииlog(null)
иlog(0)
возвращаютnull
.SELECT * FROM cypher('graph_name', $$ RETURN log(27) $$) as (natural_logarithm agtype); natural_logarithm ------------------- 3.295836866004329 (1 row)
Возвращается натуральный логарифм числа 27.
-
log10(
#expression
variadic "any"
) returns agtype float Функция
log10()
возвращает десятичный логарифм числа (по основанию 10). Функцииlog10(null)
иlog10(0)
возвращаютnull
.SELECT * FROM cypher('graph_name', $$ RETURN log10(27) $$) as (common_logarithm agtype); common_logarithm -------------------- 1.4313637641589874 (1 row)
Возвращается десятичный логарифм числа 27.
H.1.25. Тригонометрические функции #
-
degrees(
#expression
variadic "any"
) returns agtype float Функция
grades()
преобразует радианы в градусы. Функцияdegrees(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN degrees(3.14159) $$) as (deg agtype); deg ------------------- 179.9998479605043 (1 row)
Возвращается число градусов, примерно равное числу пи в радианах.
-
radians(
#expression
variadic "any"
) returns agtype float Функция
radians()
преобразует градусы в радианы. Функцияradians(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN radians(180) $$) as (rad agtype); rad ------------------- 3.141592653589793 (1 row)
Возвращается число градусов, примерно равное числу пи в радианах.
-
pi() returns agtype float
# Функция
pi()
возвращает математическую константу пи.SELECT * FROM cypher('graph_name', $$ RETURN pi() $$) as (p agtype); p ------------------- 3.141592653589793 (1 row)
Возвращается константа пи.
-
sin(
#expression
variadic "any"
) returns agtype float Функция
sin()
возвращает синус числа. Функцияsin(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN sin(0.5) $$) as (s agtype); s ------------------- 0.479425538604203 (1 row)
Возвращается синус 0.5.
-
cos(
#expression
variadic "any"
) returns agtype float Функция
cos()
возвращает косинус числа. Функцияcos(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN cos(0.5) $$) as (c agtype); c -------------------- 0.8775825618903728 (1 row)
Возвращается косинус 0.5.
-
tan(
#expression
variadic "any"
) returns agtype float Функция
tan()
возвращает тангенс числа. Функцияtan(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN tan(0.5) $$) as (t agtype); t -------------------- 0.5463024898437905 (1 row)
Возвращается тангенс 0.5.
-
cot(
#expression
variadic "any"
) returns agtype float Функция
cot()
возвращает котангенс числа. Функцияcot(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN cot(0.5) $$) as (t agtype); t ------------------- 1.830487721712452 (1 row)
Возвращается котангенс 0.5.
-
asin(
#expression
variadic "any"
) returns agtype float Функция
asin()
возвращает арксинус числа. Функцияasin(null)
возвращаетnull
. Если (выражение < -1) или (выражение > 1), тоasin(expression)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN asin(0.5) $$) as (arc_s agtype); arc_s -------------------- 0.5235987755982989 (1 row)
Возвращается арксинус 0.5.
-
acos(
#expression
variadic "any"
) returns agtype float Функция
acos()
возвращает арксинус числа. Функцияacos(null)
возвращаетnull
. Если (выражение < -1) или (выражение > 1), тоacos(expression)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN acos(0.5) $$) as (arc_c agtype); arc_c -------------------- 1.0471975511965979 (1 row)
Возвращается арккосинус 0.5.
-
atan(
#expression
variadic "any"
) returns agtype float Функция
atan()
возвращает арктангенс числа. Функцияatan(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN atan(0.5) $$) as (arc_t agtype); arc_t -------------------- 0.4636476090008061 (1 row)
Возвращается арктангенс 0.5.
-
atan2(
#expression1
variadic "any"
,expression2
variadic "any"
) returns agtype float Функция
atan()
возвращает арктангенс набора координат в радианах. Функцииatan2(null, null)
,atan2(null, expression2)
иatan(expression1, null)
возвращаютnull
.SELECT * FROM cypher('graph_name', $$ RETURN atan2(0.5, 0.6) $$) as (arc_t2 agtype); arc_t2 -------------------- 0.6947382761967033 (1 row)
Возвращается арктангенс 0.5 и 0.6.
H.1.26. Строковые функции #
-
replace(
#original
,search
variadic "any"
,replace
variadic "any"
) returns agtype string Функция
replace()
возвращает строку, в которой все вхождения первой указанной строки в исходной строке заменены другой указанной строкой. Если какой-либо аргумент имеет значениеnull
, возвращаетсяnull
. Если строка не нашлась вoriginal
, возвращаетсяoriginal
.SELECT * FROM cypher('graph_name', $$ RETURN replace('hello', 'l', 'w') $$) as (str_array agtype); str_array ----------- "hewwo" (1 row)
-
split(
#original
variadic "any"
,split_delimiter
variadic "any"
) returns list of agtype strings Функция
split()
возвращает список строк, полученный в результате разделения исходной строки по совпадениям с заданным разделителем. Функцииsplit(null, SplitDelimiter)
иsplit(original, null)
возвращаютnull
.SELECT * FROM cypher('graph_name', $$ RETURN split('one,two', ',') $$) as (split_list agtype); split_list ---------------- ["one", "two"] (1 row)
-
left(
#original
variadic "any"
,length
variadic "any"
) returns agtype string Функция
left()
возвращает строку, содержащую указанное число крайних левых символов исходной строки. Функцииleft(null, length)
иleft(null, null)
возвращаютnull
. Функцияleft(original, null)
вызывает ошибку. Еслиlength
не является целым положительным числом, также возникает ошибка. Еслиlength
превышает размерoriginal
, возвращаетсяoriginal
.SELECT * FROM cypher('graph_name', $$ RETURN left('Hello', 3) $$) as (new_str agtype); new_str --------- "Hel" (1 row)
-
right(
#original
variadic "any"
,length
variadic "any"
) returns agtype string Функция
right()
возвращает строку, содержащую указанное количество крайних правых символов исходной строки. Функцииright(null, length)
иright(null, null)
возвращаютnull
. Функцияright(original, null)
вызывает ошибку. Еслиlength
не является целым положительным числом, также возникает ошибка. Еслиlength
превышает размерparameter
, возвращаетсяoriginal
.SELECT * FROM cypher('graph_name', $$ RETURN right('hello', 3) $$) as (new_str agtype); new_str --------- "llo" (1 row)
-
substring(
#original
variadic "any"
,start
variadic "any"
[,length
variadic "any"
]) returns agtype string Функция
substring()
возвращает подстроку из исходной строки по индексу с нумерацией от 0, от начала и до конца его длины. Параметрstart
использует индекс с нуля. Еслиlength
опущен, функция возвращает подстроку, начинающуюся с позиции, заданнойstart
, и продолжающуюся до концаoriginal
. Еслиoriginal
имеет значениеnull
, возвращаетсяnull
. Еслиstart
илиlength
имеет значениеnull
или отрицательное целое число, возникает ошибка. Еслиstart
равен 0, подстрока начнётся с началаoriginal
. Еслиlength
равен 0, возвращается пустая строка.SELECT * FROM cypher('graph_name', $$ RETURN substring('hello', 1, 3), substring('hello', 2) $$) as (sub_str1 agtype, sub_str2 agtype); sub_str1 | sub_str2 ----------+---------- "ell" | "llo" (1 row)
-
rTrim(
#original
variadic "any"
) returns agtype string Функция
rTrim()
возвращает исходную строку с удалёнными конечными пробелами. ФункцияrTrim(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN rTrim(' hello ') $$) as (right_trimmed_str agtype); right_trimmed_str ------------------- " hello" (1 row)
-
lTrim(
#original
variadic "any"
) returns agtype string Функция
lTrim()
возвращает исходную строку с удалёнными начальными пробелами. ФункцияlTrim(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN lTrim(' hello ') $$) as (left_trimmed_str agtype); left_trimmed_str ------------------ "hello " (1 row)
-
trim(
#original
variadic "any"
) returns agtype string Функция
trim()
возвращает исходную строку с удалёнными начальными и конечными пробелами. Функцияtrim(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN trim(' hello ') $$) as (trimmed_str agtype); trimmed_str ------------- "hello" (1 row)
-
toLower(
#original
variadic "any"
) returns agtype string Функция
toLower()
возвращает исходную строку в нижнем регистре. ФункцияtoLower(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN toLower('HELLO') $$) as (lower_str agtype); lower_str ----------- "hello" (1 row)
-
toUpper(
#original
variadic "any"
) returns agtype string Функция
toUpper()
возвращает исходную строку в верхнем регистре.toUpper(null)
returnsnull
.SELECT * FROM cypher('graph_name', $$ RETURN toUpper('hello') $$) as (upper_str agtype); upper_str ----------- "HELLO" (1 row)
-
reverse(
#original
variadic "any"
) returns agtype string Функция
reverse()
возвращает строку с обратным порядком всех символов исходной строки. Функцияreverse(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ RETURN reverse('hello') $$) as (reverse_str agtype); reverse_str ------------- "olleh" (1 row)
-
toString(
#expression
agtype
) returns string Функция
toString()
преобразует значение типаinteger
,float
илиboolean
в строку. ФункцияtoString(null)
возвращаетnull
. Если передаваемое вexpression
выражение является строкой, оно возвращается без изменений.SELECT * FROM cypher('graph_name', $$ RETURN toString(11.5),toString('a string'), toString(true) $$) as (float_to_str agtype, str_to_str agtype, bool_to_string agtype); float_to_str | str_to_str | bool_to_string --------------+------------+---------------- "11.5" | "a string" | "true" (1 row)
H.1.27. Агрегатные функции #
Функции, активирующие автоматическое агрегирование.
LOAD 'age'; SET search_path TO ag_catalog; SELECT create_graph('graph_name'); SELECT * FROM cypher('graph_name', $$ CREATE (a:Person {name: 'A', age: 13}), (b:Person {name: 'B', age: 33, eyes: 'blue'}), (c:Person {name: 'C', age: 44, eyes: 'blue'}), (d1:Person {name: 'D', eyes: 'brown'}), (d2:Person {name: 'D'}), (a)-[:KNOWS]->(b), (a)-[:KNOWS]->(c), (a)-[:KNOWS]->(d1), (b)-[:KNOWS]->(d2), (c)-[:KNOWS]->(d2) $$) as (a agtype);
-
min(
#expression
variadic "any"
) returns agtype Функция
min()
возвращает минимальное значение в наборе значений. Любые значенияnull
исключаются из вычисления. В наборе значений разных типов любое строковое значение всегда считается меньше, чем любое числовое значение, а любой список всегда считается меньше, чем любая строка. Списки сравниваются в словарном порядке, т. е. элементы списка сравниваются попарно в порядке возрастания от начала списка к концу. Функцияmin(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ MATCH (v:Person) RETURN min(v.age) $$) as (min_age agtype); min_age --------- 13 (1 row)
Возвращается наименьшее из всех значений свойства
age
.Чтобы пояснить следующий пример, предположим, что сначала выполняются следующие три команды:
SELECT * FROM cypher('graph_name', $$ CREATE (:min_test {val:'d'}) $$) as (result agtype); SELECT * FROM cypher('graph_name', $$ CREATE (:min_test {val:['a', 'b', 23]}) $$) as (result agtype); SELECT * FROM cypher('graph_name', $$ CREATE (:min_test {val:[1, 'b', 23]}) $$) as (result agtype);
В примере ниже показано использование функции
min()
со списками:SELECT * FROM cypher('graph_name', $$ MATCH (v:min_test) RETURN min(v.val) $$) as (min_val agtype); min_val ---------------- ["a", "b", 23] (1 row)
Возвращается наименьшее из всех значений в наборе (в данном случае список
["a", "b", 23]
), поскольку два списка считаются меньшими значениями, чем строка «d», а строка «a» считается меньшим значением, чем числовое значение 1.-
max(
#expression
variadic "any"
) returns agtype float Функция
max()
возвращает максимальное значение в наборе значений. Любые значенияnull
исключаются из вычислений. В наборе значений разных типов любое строковое значение всегда считается меньше, чем любое числовое значение, а любой список всегда считается меньше, чем любая строка. Списки сравниваются в словарном порядке, т. е. элементы списка сравниваются попарно в порядке возрастания от начала списка к концу. Функцияmax(null)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ MATCH (n:Person) RETURN max(n.age) $$) as (max_age agtype); max_age --------- 44 (1 row)
Возвращается наибольшее из всех значений свойства
age
.-
stDev(
#expression
variadic "any"
) returns agtype float Функция
stDev()
возвращает стандартное отклонение для заданного значения по группе. Она применяет стандартный двухпроходный метод с N - 1 в качестве знаменателя и должна использоваться при выборке совокупности для получения несмещённой оценки. При расчёте стандартного отклонения для всей совокупности следует использоватьstDevP
. Любые значенияnull
исключаются из вычисления. ФункцияstDev(null)
возвращает 0.0 (ноль).SELECT * FROM cypher('graph_name', $$ MATCH (n:Person) RETURN stDev(n.age) $$) as (stdev_age agtype); stdev_age -------------------- 15.716233645501712 (1 row)
Возвращается стандартное отклонение значений свойства
age
.-
stDevP(
#expression
variadic "any"
) returns agtype float Функция
stDev()
возвращает стандартное отклонение для заданного значения по группе. Она применяет стандартный двухпроходный метод с N в качестве знаменателя и должна использоваться при расчёте стандартного отклонения для всей совокупности. Когда рассчитывается стандартное отклонение только выборки совокупности, следует использоватьstDev
. Любые значенияnull
исключаются из вычисления.stDevP(null)
возвращает 0.0 (ноль).SELECT * FROM cypher('graph_name', $$ MATCH (n:Person) RETURN stDevP(n.age) $$) as (stdevp_age agtype); stdevp_age -------------------- 12.832251036613439 (1 row)
Возвращается стандартное отклонение совокупности значений свойства
age
.-
percentileCont(
#expression
agtype
,percentile
agtype
) returns agtype float Функция
percentileCont()
возвращает процентиль заданного значения для группы с процентилем от 0.0 до 1.0. Она использует метод линейной интерполяции, вычисляя средневзвешенное значение между двумя значениями, если желаемый процентиль находится между ними. Получить ближайшие значения с применением метода округления можно с помощью функцииpercentileDisc
. Любые значенияnull
исключаются из вычисления. ФункцияpercentileCont(null, percentile)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ MATCH (n:Person) RETURN percentileCont(n.age, 0.4) $$) as (percentile_cont_age agtype); percentile_cont_age --------------------- 29.0 (1 row)
Возвращается 40-й процентиль значений свойства
age
, рассчитанный с использованием средневзвешенного значения. В данном случае 0.4 — это медиана или 40-й процентиль.-
percentileDisc(
#expression
agtype
,percentile
agtype
) returns agtype float Функция
percentileDisc()
возвращает процентиль заданного значения для группы с процентилем от 0.0 до 1.0. Она использует метод округления и вычисляет ближайшее значение к процентилю. Интерполированные значения можно получить с помощью функцииpercentileCont
. Любые значенияnull
исключаются из вычисления. ФункцияpercentileDisc(null, percentile)
возвращаетnull
.SELECT * FROM cypher('graph_name', $$ MATCH (n:Person) RETURN percentileDisc(n.age, 0.5) $$) as (percentile_disc_age agtype); percentile_disc_age --------------------- 33.0 (1 row)
Возвращается 50-й процентиль значений свойства
age
.-
count(
#expression
agtype
) returns agtype integer Функция
count()
возвращает количество значений или записей и существует в двух вариантах:Функция
count(*)
возвращает число совпадающих записей.Функция
count(expr)
возвращает количество возвращаемых выражением значений, не являющихся null.
Функция
count(*)
включает записи, возвращающиеnull
. Функцияcount(expr)
игнорирует значенияnull
. Функцияcount(null)
возвращает 0 (ноль). Функциюcount(*)
можно использовать для возвращения количества узлов: например, количества узлов, подключённых к некоторому узлуn
.SELECT * FROM cypher('graph_name', $$ MATCH (n {name: 'A'})-[]->(x) RETURN n.age, count(*) $$) as (age agtype, number_of_people agtype); age | number_of_people -----+------------------ 13 | 3 (1 row)
Возвращаются свойство
age
начального узлаn
(со значением имени «A») и количество узлов, связанных сn
.Функцию
count(*)
можно использовать для группировки и подсчёта типов отношений, она возвращает количество отношений каждого типа.SELECT * FROM cypher('graph_name', $$ MATCH (n {name: 'A'})-[r]->() RETURN type(r), count(*) $$) as (label agtype, count agtype); label | count ---------+------- "KNOWS" | 3 (1 row)
Возвращаются тип связи и количество связей этого типа.
Вместо того, чтобы использовать функцию
count(*)
для обычного получения значений, может оказаться более полезным вернуть фактическое количество значений, возвращаемых выражением.SELECT * FROM cypher('graph_name', $$ MATCH (n {name: 'A'})-[]->(x) RETURN count(x) $$) as (count agtype); count ------- 3 (1 row)
Возвращается количество узлов, подключённых к начальному узлу
n
.Функцию
count(expression)
можно использовать для получения количества выводимых выражением значений, не являющихся null.SELECT * FROM cypher('graph_name', $$ MATCH (n:Person) RETURN count(n.age) $$) as (count agtype); count ------- 3 (1 row)
Возвращается количество узлов с меткой
Person
, которые имеют значение свойстваage
, не являющееся null.В следующем примере мы пытаемся найти всех друзей наших друзей и посчитать их. Первая агрегатная функция,
count(DISTINCT friends_of_friend)
, будет учитывать друг друга (friend_of_friend
) только один раз, поскольку при указанииDISTINCT
удаляются дубликаты. Вторая агрегатная функция,count(friend_of_friend)
, будет рассматривать одного и то жеfriend_of_friend
несколько раз.SELECT * FROM cypher('graph_name', $$ MATCH (me:Person)-[]->(friend:Person)-[]->(friend_of_friend:Person) WHERE me.name = 'A' RETURN count(DISTINCT friend_of_friend), count(friend_of_friend) $$) as (friend_of_friends_distinct agtype, friend_of_friends agtype); friend_of_friends_distinct | friend_of_friends ----------------------------+------------------- 1 | 2 (1 row)
Как B, так и C знают D, поэтому D будет учитываться дважды, если не использовать
DISTINCT
.-
avg(
#expression
agtype
) returns agtype integer Функция
avg()
возвращает среднее значение набора числовых значений. Любые значенияnull
исключаются из вычисления. Функцияavg(null)
возвращает значение null.SELECT * FROM cypher('graph_name', $$ MATCH (n:Person) RETURN avg(n.age) $$) as (avg_age agtype); avg_age --------- 30.0 (1 row)
Возвращается среднее значение всех свойств
age
.-
sum(
#expression
agtype
) returns agtype float Функция
sum()
возвращает сумму набора числовых значений. Любые значенияnull
исключаются из вычисления. Функцияsum(null)
возвращает ноль.SELECT * FROM cypher('graph_name', $$ MATCH (n:Person) RETURN sum(n.age) $$) as (total_age agtype); total_age ----------- 90 (1 row)
Возвращается сумма всех значений свойства
age
.
H.1.28. Пользовательские функции #
Пользователи могут добавлять собственные функции в apache_age. При использовании Cypher-функций все вызовы функций с Cypher-запросом используют пространство имён по умолчанию: ag_catalog
. Однако если пользователь хочет использовать функцию за пределами этого пространства имён, нужно указать нужное пространство имён перед именем функции.
Синтаксис: имя_пространства_имён.имя_функции
SELECT * FROM cypher('graph_name', $$ RETURN pg_catalog.sqrt(25) $$) as (result agtype); result -------- 25 (1 row)
H.1.29. apache_age за рамками языка Cypher #
До сих пор все запросы выполнялись по одному и тому же шаблону: предложение SELECT
, за которым следовал одиночный вызов Cypher в предложении FROM
. Однако Cypher-запрос можно использовать многими другими способами. В этом разделе описываются некоторые более продвинутые способы вызова Cypher в более сложных гибридных запросах SQL/Cypher.
H.1.29.1. Использование Cypher в CTE #
Нет никаких ограничений на использование Cypher с CTE (общими табличными выражениями).
WITH graph_query as ( SELECT * FROM cypher('graph_name', $$ MATCH (n) RETURN n.name, n.age $$) as (name agtype, age agtype) ) SELECT * FROM graph_query; name | age -----------+----- "Andres" | 36 "Tobias" | 25 "Peter" | 35 (3 rows)
H.1.29.2. Использование Cypher в выражениях JOIN #
Cypher-запрос может быть частью предложения JOIN
.
Примечание
Cypher-запросы с использованием предложений CREATE
, SET
, REMOVE
нельзя использовать в SQL-запросах с JOIN, поскольку они влияют на систему транзакций Postgres Pro. Чтобы обойти данное ограничение, можно защитить запрос с помощью CTE.
SELECT id, graph_query.name = t.name as names_match, graph_query.age = t.age as ages_match FROM schema_name.sql_person AS t JOIN cypher('graph_name', $$ MATCH (n:Person) RETURN n.name, n.age, id(n) $$) as graph_query(name agtype, age agtype, id agtype) ON t.person_id = graph_query.id; id | names_match | ages_match ---+-------------+------------ 1 | True | True 2 | False | True 3 | True | False (3 rows)
H.1.29.3. Cypher в SQL-выражениях #
Cypher нельзя использовать в выражениях, запрос должен существовать в предложении FROM
запроса. Однако если запрос Cypher используется в подзапросе, он будет действовать как любой запрос в стиле SQL.
H.1.29.3.1. Использование Cypher с =
#
При написании Cypher-запроса, возвращающего 1 столбец и 1 строку, можно использовать оператор сравнения =
.
SELECT t.name FROM schema_name.sql_person AS t where t.name = ( SELECT a FROM cypher('graph_name', $$ MATCH (v) RETURN v.name $$) as (name varchar(50)) ORDER BY name LIMIT 1); name | age ----------+----- "Andres" | 36 (1 rows)
H.1.29.3.2. Работа с предложением IN Postgres Pro #
При написании Cypher-запроса, возвращающего 1 столбец, но несколько строк, можно использовать оператор IN
.
SELECT t.name, t.age FROM schema_name.sql_person as t where t.name in ( SELECT * FROM cypher('graph_name', $$ MATCH (v:Person) RETURN v.name $$) as (a agtype)); name | age -----------+----- "Andres" | 36 "Tobias" | 25 "Peter" | 35 (3 rows)
H.1.29.3.3. Работа с предложением EXISTS Postgres Pro #
При написании запроса Cypher, возвращающего более 1 столбца и строки, можно использовать оператор EXISTS
.
SELECT t.name, t.age FROM schema_name.sql_person as t WHERE EXISTS ( SELECT * FROM cypher('graph_name', $$ MATCH (v:Person) RETURN v.name, v.age $$) as (name agtype, age agtype) WHERE name = t.name AND age = t.age ); name | age -----------+----- "Andres" | 36 "Tobias" | 25 "Peter" | 35 (3 rows)
H.1.29.3.4. Запрос к нескольким графам #
В SQL-операторе можно обращаться к любому количеству графов одновременно.
SELECT graph_1.name, graph_1.age, graph_2.license_number FROM cypher('graph_1', $$ MATCH (v:Person) RETURN v.name, v.age $$) as graph_1(col_1 agtype, col_2 agtype, col_3 agtype) JOIN cypher('graph_2', $$ MATCH (v:Doctor) RETURN v.name, v.license_number $$) as graph_2(name agtype, license_number agtype) ON graph_1.name = graph_2.name name | age | license_number -----------+-----+---------------- "Andres" | 36 | 1234567890 (1 rows)
H.1.29.4. Подготовленные операторы #
Cypher может выполнить запрос на чтение внутри подготовленного оператора. При использовании параметров с хранимыми процедурами SQL-параметр должен быть помещён в вызов функции Cypher. За более подробной информацией обратитесь к разделу Формат запросов apache_age.
Параметры в Cypher используются в таком формате: «$» и идентификатор. В отличие от параметров Postgres Pro, параметры Cypher начинаются с буквы, за которой следует буквенно-цифровая строка произвольной длины. Пример: $
имя_параметра
Использование подготовленных операторов в Cypher является расширением системы хранимых процедур Postgres Pro. Используйте предложение PREPARE
, чтобы создать запрос с вызовом функции Cypher. Не размещайте параметры стиля Postgres Pro в вызове Cypher-запроса, вместо этого поместите параметры Cypher в запрос, а параметр Postgres Pro — в качестве третьего аргумента в вызове функции Cypher.
PREPARE cypher_stored_procedure(agtype) AS SELECT * FROM cypher('expr', $$ MATCH (v:Person) WHERE v.name = $name //параметр Cypher RETURN v $$, $1) //An SQL Parameter must be placed in the Cypher function call AS (v agtype);
При выполнении подготовленного оператора поместите значение типа agtype map
со значениями параметров туда, где находится параметр Postgres Pro в вызове функции Cypher. Значение должно иметь тип agtype map
, иначе возникнет ошибка, а также следует исключить «$» в именах параметров.
EXECUTE cypher_prepared_statement('{'name': 'Tobias'}');
H.1.29.5. Функции PL/pgSQL #
Команды Cypher можно без ограничений выполнять в функциях PL/pgSQL.
SELECT * FROM cypher('imdb', $$ CREATE (toby:actor {name: 'Toby Maguire'}), (tom:actor {name: 'Tom Holland'}), (willam:actor {name: 'Willam Dafoe'}), (robert:actor {name: 'Robert Downey Jr'}), (spiderman:movie {title: 'Spiderman'}), (no_way_home:movie {title: 'Spiderman: No Way Home'}), (homecoming:movie {title: 'Spiderman: Homecoming'}), (ironman:movie {title: 'Ironman'}), (tropic_thunder:movie {title: 'Tropic Thunder'}), (toby)-[:acted_in {role: 'Peter Parker', alter_ego: 'Spiderman'}]->(spiderman), (willam)-[:acted_in {role: 'Norman Osborn', alter_ego: 'Green Goblin'}]->(spiderman), (toby)-[:acted_in {role: 'Toby Maguire'}]->(tropic_thunder), (robert)-[:acted_in {role: 'Kirk Lazarus'}]->(tropic_thunder), (robert)-[:acted_in {role: 'Tony Stark', alter_ego: 'Ironman'}]->(homecoming), (tom)-[:acted_in {role: 'Peter Parker', alter_ego: 'Spiderman'}]->(homecoming), (tom)-[:acted_in {role: 'Peter Parker', alter_ego: 'Spiderman'}]->(no_way_home), (toby)-[:acted_in {role: 'Peter Parker', alter_ego: 'Spiderman'}]->(no_way_home), (willam)-[:acted_in {role: 'Norman Osborn', alter_ego: 'Green Goblin'}]->(no_way_home) $$) AS (a agtype);
Пример создания функции показан ниже.
CREATE OR REPLACE FUNCTION get_all_actor_names() RETURNS TABLE(actor agtype) LANGUAGE plpgsql AS $BODY$ BEGIN LOAD 'age'; SET search_path TO ag_catalog; RETURN QUERY SELECT * FROM ag_catalog.cypher('imdb', $$ MATCH (v:actor) RETURN v.name $$) AS (a agtype); END $BODY$;
Выполните запрос:
SELECT * FROM get_all_actor_names(); actor -------------------- "Toby Maguire" "Tom Holland" "Willam Dafoe" "Robert Downey Jr" (4 rows)
Примечание
Рекомендуется добавить команду LOAD 'age'
и задать search_path
в объявлении функции, чтобы обеспечить согласованную работу команды CREATE FUNCTION
.
H.1.29.5.1. Пример динамического Cypher-запроса #
CREATE OR REPLACE FUNCTION get_actors_who_played_role(role agtype) RETURNS TABLE(actor agtype, movie agtype) LANGUAGE plpgsql AS $function$ DECLARE sql VARCHAR; BEGIN load 'age'; SET search_path TO ag_catalog; sql := format(' SELECT * FROM cypher(''imdb'', $$ MATCH (actor)-[:acted_in {role: %s}]->(movie:movie) RETURN actor.name, movie.title $$) AS (actor agtype, movie agtype); ', role); RETURN QUERY EXECUTE sql; END $function$;
SELECT * FROM get_actors_who_played_role('"Peter Parker"'); actor | movie ----------------+-------------------------- "Toby Maguire" | "Spiderman: No Way Home" "Toby Maguire" | "Spiderman" "Tom Holland" | "Spiderman: Homecoming" "Tom Holland" | "Spiderman: No Way Home" (4 rows)
H.1.29.6. SQL в Cypher #
Расширение apache_age не поддерживает использование языка SQL непосредственно в Cypher-запросах. Однако с помощью пользовательских функций можно писать SQL-запросы и вызывать их командами Cypher.
Примечание
Это относится только к скалярным функциям и функциям void. Функции возвращения множеств в настоящее время не поддерживаются.
Создание функции:
CREATE OR REPLACE FUNCTION public.get_event_year(name agtype) returns agtype AS $$ SELECT year::agtype FROM history AS h WHERE h.event_name = name::text LIMIT 1; $$ LANGUAGE sql;
SELECT * FROM cypher('graph_name', $$ MATCH (e:event) WHERE e.year < public.get_event_year(e.name) RETURN n.name $$) as (n agtype); n ------------------- "Apache Con 2021" (1 row)