AGE使用自定义数据类型Agtype,且是返回的唯一数据类型。Agtype是JSON的超集,并且是一种自定义实现的JsonB。
简单数据类型
简单数据类型(也称基本数据类型)指最基础的数据单位,通常由编程语言直接支持,且可以直接存储在变量中。这些数据类型包括整数、浮点数、字符和布尔值等。下面我们将详细介绍每一种简单数据类型:
NULL:用于表示缺失或未定义的值。
整数:用于表示没有小数部分的数字。例如,在Python中,可以使用
int
来声明一个整数类型的变量。浮点数:用于表示带有小数部分的数字。例如,在Python中,可以使用
float
表示浮点数的数据类型。数值:用于存储具有大量数字位数的数值。
布尔值:用于表示真或假的状态。大多数编程语言使用
bool
类型来表示布尔值,其中True
代表真,False
代表假。字符串:用于表示单个字符。在许多编程语言中,如C或Java,字符类型通常用
char
表示。
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中的NULL概念相同。
整数
整数类型(Integer)用于存储整数,即没有小数部分的数字。整数数据类型是一个64位字段,可以存储从-9,223,372,036,854,775,808到9,223,372,036,854,775,807的值。尝试存储超出此范围的值将导致错误。
整数类型是常见的选择,因为它在范围、存储大小和性能之间提供了最佳平衡。smallint
类型通常只在磁盘空间非常紧张的情况下使用。bigint
类型则适用于整数类型的范围无法满足需求的场景。
输入/输出格式
SELECT * FROM cypher('graph_name', $$
RETURN 1
$$) AS (int_result agtype);
返回结果如下:
int_result
------------
1
(1 row)
浮点数
浮点数(Float)是一种不精确的、可变精度的数值类型,符合IEEE-754标准。
"不精确"意味着某些值无法精确转换为内部格式,而是以近似值存储,因此存储和检索一个值时可能会出现细微差异。管理这些误差以及它们在计算中的传播是数学和计算机科学的一个专门领域,在此不做详细讨论,但有以下几点需要注意:
如果需要精确存储和计算(例如货币金额),请使用数值类型。
如果需要进行复杂计算,且这些计算非常重要,特别是这些计算还依赖于边界情况的行为(如无穷大、下溢),需要仔细评估实现细节。
比较两个浮点值是否相等的结果可能不会始终与预期结果一致。
当浮点数过大或过小,将会导致错误。如果输入数字的精度太高,可能会进行舍入。过于接近零且无法表示为与零不同的值将导致下溢错误。
除普通的数值之外,浮点数还包含以下特殊值,用于表示IEEE 754特殊值:
正无穷大(Infinity)
负无穷大(-Infinity)
非数字(NaN)
在Cypher命令中将这些值作为常量写入时,必须将它们放在引号中并进行类型转换,例如:
SET x.float_value = '-Infinity'::float
在输入时,这些字符串以大小写不敏感的方式被识别。
IEEE-754标准规定,非数字(NaN)不应与任何其他浮点值(包括 NaN 本身)相等。然而,为了使浮点数正确排序,AGE将'NaN'::float = 'NaN'::float
评估为true
。更多详细介绍请参考可比较性、相等性、有序性和等价性。
输入/输出格式
使用浮点数,表示一个带有小数的值。
SELECT * FROM cypher('graph_name', $$
RETURN 1.0
$$) AS (float_result agtype);
返回结果如下:
float_result
--------------
1.0
(1 row)
数值
数值类型(Numeric)用于存储具有大量数字位数的数值,特别适用于存储货币金额和其他需要精确性的数值。使用数值类型进行计算时,能够直接通过基本运算获得精确的结果,例如加法、减法和乘法。然而,与整数类型或浮点类型相比,数值类型的计算速度较慢。
相关概念
精度:Numeric的精度是整个数字中所有有效数字的总数,即小数点两边的数字总数。
标度:Numeric的标度是小数部分中小数点右侧的小数位数。
因此,数字23.5141的精度为6,标度为4。整数可以被认为具有零标度。
如不指定任何精度或标度,则会创建一个可以存储任意精度和标度的数值列,直到达到实现所允许精度的上限。数值列并不强制要求输入值满足特定标度,而声明了标度的Numeric列则会将输入值强制转换为该标度。
SQL标准要求默认标度为0,即强制转换为整数精度。社区官方认为这点无用。如果担心可移植性,请始终显式指定精度和标度。
在类型声明中显式指定的最大允许精度为1000,未指定精度的NUMERIC受表 8.2 中描述的限制影响。
如果需要存储的值的标度大于列的声明标度,系统将把值四舍五入到指定的小数位数。然后,如果小数点左边的数字位数超过声明精度减去声明标度的值,将引发错误。
numeric
在物理存储时不带有额外的前导或尾随零。因此,列的声明精度和标度是最大值,而不是固定的分配(从这个意义上说,numeric
类型更像 varchar(n)
而不是 char(n)
)。实际的存储需求是每四个十进制数字组两个字节,加上三到八个字节的额外开销。
除了普通的数值外,numeric
类型还允许特殊的值NaN,表示“非数字”。任何对NaN的操作都会得到另一个NaN。在SQL命令中将此值作为常量写入时,必须在其周围加上引号,例如:
UPDATE table SET x = 'NaN'
IEEE-754标准规定,非数字(NaN)不应与任何其他数值(包括 NaN 本身)相等。然而,为了使数值正确排序,AGE将'NaN'::float = 'NaN'::float
评估为true
。更多详细介绍请参考可比较性、相等性、有序性和等价性。
在四舍五入值时,numeric
类型会将平局远离零舍入,而(在大多数机器上)实数和双精度类型会将平局舍入到最近的偶数。
在对数值进行四舍五入时,numeric
类型采用向零的反方向四舍五入(即“远离零”原则),而(在大多数计算机上)实数和双精度类型则向最近的偶数四舍五入。
输入/输出格式
创建numeric
数据类型时,需要使用::numeric
注释。
SELECT * FROM cypher('graph_name', $$
RETURN 1.0::numeric
$$) AS (numeric_result agtype);
返回结果如下:
numeric_result
----------------
1::numeric
(1 row)
布尔值
AGE提供了标准的Cypher类型boolean(布尔类型)。布尔类型可以有几种状态:“true”(真)、“false”(假),以及第三种状态“unknown”(未知),由Agtype的NULL表示。
在Cypher查询中,布尔常量使用关键字TRUE、FALSE和NULL来表示。
输入/输出格式
SELECT * FROM cypher('graph_name', $$
RETURN TRUE
$$) AS (boolean_result agtype);
与PostgreSQL不同,AGE的布尔输出为完整的单词,即true
和false
,而不是t
和f
。返回结果如下:
boolean_result
----------------
true
(1 row)
字符串
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)
复合数据类型
复合数据类型是由一个或多个简单数据类型组合而成的数据结构,能够存储和操作更为复杂的信息。以下是一些常见的复合数据类型:
数组(Array):一种线性数据结构,其元素具有相同的类型,并且可通过索引进行访问。
列表(List):类似于数组,但通常提供更为灵活的插入和删除操作。
字典(Dictionary)/映射(Map):键值对的集合,通过唯一的键对值进行访问。
集合(Set):不包含重复元素的无序集合。
元组(Tuple):固定大小的有序集合,可包含多种类型的元素。
每种复合数据类型都有其特定的用途和优势,在不同的场景中发挥着重要作用。选择合适的数据类型对于编写高效、可维护的代码至关重要。
列表
所有示例将使用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)
列表中的映射元素
示例
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 (element agtype);
返回结果如下:
element
--------------------
[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)
映射
可使用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)
简单实体
实体具有唯一且可比较的身份,用于定义两个实体是否相等。
实体被分配了一组属性,每个属性在该集合中通过其独特的属性键来识别。
GraphId
简单实体被分配一个唯一的GraphId。GraphId是由实体的标签ID及分配给每个标签的唯一序列所组成的唯一组合。需注意的是,当比较来自不同图的实体时,ID可能会出现重叠。
标签
标签作为一种标识符,用于将顶点和边归类到特定类别中。
边必须有标签,但顶点不需要。
顶点和边之间的标签名称不能重复。
如何创建带标签的实体的详细信息,请参见CREATE。
属性
顶点和边都可以具有属性。属性是属性值,每个属性名称应仅定义为字符串类型。
顶点
顶点是图的基本实体,具有能够独立存在的独特属性。
一个顶点可以被赋予一个标签。
顶点可能有零个或多个出边。
顶点可能有零个或多个入边。
数据格式:
属性名称 | 描述 |
id | 此顶点的GraphId。 |
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)
边
边是一个实体,它编码了两个节点之间的有向连接,即源节点和目标节点。从源节点的角度来看,出边是一种有向关系。从目标节点的角度来看,入边是一种有向关系。每个边被分配一个唯一的边类型。
数据格式:
属性名称 | 描述 |
id | 此顶点的GraphId。 |
startid | 源节点的GraphId。 |
endid | 目标节点的GraphId。 |
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)
复合实体
复合实体是指由多个部分或子实体组成的实体。这些子实体可以是简单的数据类型,也可以是其他复合实体。在编程和数据结构中,复合实体常用于表示复杂的数据模型,如对象、数组或记录。
路径
路径(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": {}}::vertex]::path
(1 row)