数据类型

AGE 使用名为 agtype 的自定义数据类型,这是 AGE 返回的唯一数据类型。Agtype 是 JSON 的超集,也是 JsonB 的自定义实现。

简单数据类型

Null

在 Cypher 中,null 用于表示缺失或未定义的值。从概念上讲,null 意味着"一个缺失的未知值",它的处理方式与其他值有所不同。例如,从一个不具有某属性的顶点获取该属性会产生 null。大多数以 null 作为输入的表达式会产生 null。这包括在 WHERE 子句中用作谓词的布尔表达式。在这种情况下,任何不为 true 的值都被解释为 false。null 不等于 null。不知道两个值并不意味着它们是相同的值。因此表达式 null = null 产生 null 而不是 true。

输入/输出格式

查询

SELECT *
FROM cypher('graph_name', $$
    RETURN NULL
$$) AS (null_result agtype);

null 将显示为空白。

结果:

 null_result
-------------

(1 row)

Agtype NULL 与 Postgres NULL

Agtype 和 Postgres 中 NULL 的概念与 Cypher 中的相同。

Integer

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)

Float

float 数据类型是一种不精确的、可变精度的数值类型,符合 IEEE-754 标准。

不精确意味着某些值无法精确转换为内部格式,而是以近似值存储,因此存储和检索值时可能会出现轻微差异。管理这些误差及其在计算中的传播是数学和计算机科学的一个完整分支的主题,此处不做讨论,但需注意以下几点:

  • 如果您需要精确存储和计算(例如货币金额),请改用 numeric 类型。
  • 如果您要对这些类型进行复杂计算,特别是依赖于边界情况(无穷大、下溢)的某些行为,应仔细评估实现。
  • 比较两个浮点值是否相等可能并不总是按预期工作。

过大或过小的值将导致错误。如果输入数字的精度过高,可能会进行舍入。太接近零而无法表示为与零不同的数字将导致下溢错误。

除了普通数值外,浮点类型还有几个特殊值:

  • Infinity
  • -Infinity
  • NaN

这些分别表示 IEEE 754 的特殊值"正无穷"、"负无穷"和"非数字"。在 Cypher 命令中将这些值作为常量写入时,必须用引号括起来并进行类型转换,例如:

SET x.float_value = '-Infinity'::float

在输入时,这些字符串以不区分大小写的方式识别。

输入/输出格式:

要使用 float,请标注小数值。

查询

SELECT *
FROM cypher('graph_name', $$
    RETURN 1.0
$$) AS (float_result agtype);

结果:

 float_result
--------------
 1.0
(1 row)    

mxnumeric(加速上线中……)

Bool

AGE 提供标准的 Cypher boolean 类型。boolean 类型可以有几种状态:truefalse 和第三种状态 unknow,由 Agtype null 值表示。

布尔常量可以在 Cypher 查询中使用关键字 TRUEFALSENULL 表示。

输入/输出格式

查询

SELECT *
FROM cypher('graph_name', $$
    RETURN TRUE
$$) AS (boolean_result agtype);

与 Postgres 不同,AGE 的布尔值输出完整单词,即 true 和 false,而不是 t 和 f。

结果:

 boolean_result
----------------
 true
(1 row)      

String

Agtype 字符串字面量可以包含以下转义序列:

转义序列 字符
\t 制表符
\b 退格
\n 换行
\r 回车
\f 换页
' 单引号
" 双引号
\ 反斜杠
\uXXXX Unicode UTF-16 码点(\u 后必须跟 4 个十六进制数字)

输入/输出格式

使用单引号 (') 标识字符串。输出将使用双引号 (")。

查询

SELECT *
FROM cypher('graph_name', $$
    RETURN 'This is a string'
$$) AS (string_result agtype);

结果:

   string_result
--------------------
 "This is a string"
(1 row)           

复合数据类型

List

所有示例将使用 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 值不同,它会在列表中显示为单词 '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)

列表中的 Map 元素

查询

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)                                             

访问列表中的 Map 元素

查询

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)           

Map

可以使用 Cypher 构建 Map。

使用简单数据类型的字面量 Map

可以使用简单的 agtype 构建一个简单的 map。

查询

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)

使用复合数据类型的字面量 Map

Map 也可以包含复合数据类型,即列表和其他 map。

查询

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)                                                              

Map 的属性访问

查询

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)

访问 Map 中的列表元素

查询

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)        

简单实体

实体具有唯一的、可比较的标识,用于定义两个实体是否相等。

实体被分配一组属性,每个属性在集合中由其各自的属性键唯一标识。

GraphId

简单实体被分配一个唯一的 graphid。graphid 是实体标签 id 和分配给每个标签的唯一序列的唯一组合。注意,比较来自不同图的实体时,id 可能会重叠。

GraphID 本质上是一个 64 位有符号整数 (int64)

64 位被分为两部分:

|<--- 16 bits --->|<----------- 48 bits ----------->|
| Label ID | Entry ID |
| (bits 63-48) | (bits 47-0) |

  • Label ID(标签 ID):高 16 位,取值范围 1 ~ 65535(PG_UINT16_MAX),0 为无效值
  • Entry ID(条目 ID):低 48 位,取值范围 1 ~ 281474976710655(0x0000ffffffffffff),0 为无效值

Labels

标签是将顶点和边分类到特定类别的标识符。

  • 边必须有标签,但顶点不是必须的。
  • 顶点和边之间的标签名称不能重叠。

有关如何创建带标签的实体的信息,请参阅 CREATE 子句。

注意! 在 YMatrix AGE 中,将标签实现为 TABLE ,即一个 LABEL 于一个 TABLE 一一对应。

Properties

顶点和边都可以有属性。属性是属性值,每个属性名称应仅定义为字符串类型。

Vertex

  • Vertex 是图的基本实体,具有能够独立存在的唯一属性。
  • Vertex 可以被分配一个标签。
  • Vertex 可以有零个或多个出边。
  • Vertex 可以有零个或多个入边。

数据格式:

属性名称 描述
Id 此顶点的 graphid
label 此顶点的标签名称
properties 与此顶点关联的属性
{id:1; label: 'label_name'; properties: {prop1: value1, prop2: value2}}::vertex

将 Map 类型转换为 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)                                                         

Edge

Edge 是一个实体,编码两个节点之间的有向连接,即源节点和目标节点。出边是从源节点角度看的有向关系。入边是从目标节点角度看的有向关系。边被分配恰好一个边类型。

数据格式:

属性名称 描述
id 此边的 graphid
startid 源节点的 graphid
endid 目标节点的 graphid
label 此边的标签名称
properties 与此边关联的属性

输出:

{id: 3; startid: 1; endid: 2; label: 'edge_label' properties{prop1: value1, prop2: value2}}::edge

将 Map 类型转换为 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)                                                                                   

复合实体

Path

Path 是一系列交替的顶点和边。Path 必须以顶点开始,并且至少有一条边。

将 List 类型转换为 Path

查询

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": {}}::ve
rtex]::path
(1 row)