Azure Cosmos DB 由 Microsoft 提供,是全球分布的多模型数据库服务。 可快速创建和查询文档、键/值和图形数据库,所有这些都受益于 Azure Cosmos DB 核心的全球分布和水平缩放功能。

本快速入门演示如何使用 Azure 门户创建 Azure Cosmos DB Gremlin API 帐户、数据库和图(容器),并使用 Apache TinkerPop Gremlin 控制台 处理 Gremlin API 数据。 本教程将创建并查询顶点和边缘,更新顶点属性,查询顶点,遍历图形,然后删除顶点。

Gremlin 控制台基于 Groovy/Java,在 Linux、Mac 和 Windows 上运行。 可以从 Apache TinkerPop 站点 下载它。

需要使用 Azure 订阅为本快速入门教程创建 Azure Cosmos DB 帐户。

如果没有 Azure 订阅 ,请在开始之前创建一个 Azure 免费帐户

还需要安装 Gremlin 控制台 。 推荐的版本为 v3.4.13。 (若要在 Windows 上使用 Gremlin 控制台,需要安装 java 运行时 ,至少需要 Java 8,但最好使用 Java 11)。

创建数据库帐户

  • 在新浏览器窗口中,登录到 Azure 门户

  • 在左侧菜单中,选择“创建资源”。

  • 在“新建”页上,选择“数据库” “Azure Cosmos DB”。

  • 在“创建 Azure Cosmos DB 帐户”页中,输入新 Azure Cosmos DB 帐户的设置。

    输入唯一的名称 输入标识此 Azure Cosmos DB 帐户的唯一名称。 帐户 URI 将是追加到唯一帐户名称的“gremlin.azure.com”

    帐户名称只能使用小写字母、数字及连字符 (-),必须为 3 到 44 个字符长。 Gremlin(图形) API 确定要创建的帐户的类型。 Azure Cosmos DB 提供五种 API:适用于文档数据库的 NoSQL、适用于图形数据库的 Gremlin、适用于文档数据库的 MongoDB、Azure 表和 Cassandra。 必须为每种 API 创建单独的帐户。

    选择“Gremlin (图)”,因为本快速入门将创建使用 API for Gremlin 的表。

    详细了解 API for Gremlin 。 离用户最近的区域 选择用于托管 Azure Cosmos DB 帐户的地理位置。 使用离用户最近的位置,使他们能够以最快的速度访问数据。 预配吞吐量或无服务器 选择“预配吞吐量”以在 预配吞吐量 模式下创建帐户。 选择“无服务器”以在 无服务器 模式下创建帐户。 应用 Azure Cosmos DB 免费层折扣 “应用”或“不应用” 使用 Azure Cosmos DB 免费层,你将在帐户中获得每秒前 1000 RU 的免费吞吐量和 25 GB 的免费存储。 了解 免费层 的详细信息。
  • 备份策略 - 配置 定期 连续 备份策略。
  • 加密 - 使用服务管理的密钥或 客户管理的密钥
  • 标记 - 标记是名称/值对,通过将相同的标记应用到多个资源和资源组,可以对资源进行分类并查看合并的账单。
  • 选择“查看 + 创建”。

  • 创建帐户需要几分钟时间。 等待门户中显示“祝贺你! 已创建 Azure Cosmos DB 帐户”页。

    数据库 ID sample-database 输入“sample-database”作为新数据库的名称。 数据库名称的长度必须为 1 到 255 个字符,不能包含 / \ # ? 或尾随空格。 400 RU 将吞吐量更改为每秒 400 个请求单位 (RU/s)。 如果想要减少延迟,以后可以增加吞吐量。 如果选择 无服务器 容量模式,则不需要吞吐量。 图形 ID sample-graph 输入“sample-graph”作为新集合的名称。 图形名称与数据库 ID 的字符数要求相同。 所有 Azure Cosmos DB 帐户都需要一个分区键才能进行水平缩放。 在 图形数据分区 一文中了解如何选择适当的分区键。

    连接到应用服务/图

  • 在启动 Gremlin 控制台之前,请在 apache-tinkerpop-gremlin-console-3.2.5/conf 目录中创建或修改 remote-secure.yaml 配置文件。

  • 根据下表中的定义,填写 host port username password connectionPool serializer 配置:

    hosts [ account-name . gremlin .cosmos.azure.com] 请参阅下面的屏幕截图。 这是 Azure 门户的“概述”页上的“Gremlin URI”值,方括号中已删除尾部的 :443/。 注意:请确保使用 Gremlin 值,并且 不是 以 [ account-name .documents.azure.com] 结尾的 URI,这可能会在稍后尝试执行 Gremlin 查询时导致“主机未及时响应”异常。 设置为 443。 username 采用 /dbs/<db>/colls/<coll> 格式的资源,其中, <db> 是数据库名称, <coll> 是集合名称。 password 请参阅下面的第二幅屏幕截图。 这是主密钥,可以从 Azure 门户的“密钥”页上的“主密钥”框中检索到。 使用该框左侧的复制按钮可复制该值。 connectionPool {enableSsl: true} TLS 的连接池设置。 serializer { className: org.apache.tinkerpop.gremlin.
    driver.ser.GraphSONMessageSerializerV2d0,
    config: { serializeResultToString: true }} 请设置为此值,并在粘贴此值时删除所有 \n 换行符。

    对于 Hosts 值,请从“概览”页复制“Gremlin URI”值 :

    对于密码值,请从“密钥”页复制“主密钥” :

    remote-secure.yaml 文件应如下所示:

    hosts: [your_database_server.gremlin.cosmos.azure.com] 
    port: 443
    username: /dbs/your_database/colls/your_collection
    password: your_primary_key
    connectionPool: {
      enableSsl: true
    serializer: { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV2d0, config: { serializeResultToString: true }}
    

    确保将 hosts 参数的值括在括号 [] 中。

  • 在终端中运行 bin/gremlin.batbin/gremlin.sh 启动Gremlin 控制台

  • 在终端中运行 :remote connect tinkerpop.server conf/remote-secure.yaml 连接到应用服务。

    如果收到错误No appenders could be found for logger,请确保已更新 remote-secure.yaml 文件中的序列化程序值,如步骤 2 中所述。 如果配置正确,则可以安全地忽略此警告,因为它不应影响控制台的使用。

  • 接下来运行 :remote console,将所有控制台命令重定向到远程服务器。

    如果你不运行 :remote console 命令但希望将所有控制台命令重定向到远程服务器,则应在命令前添加 :> 前缀,例如,应该以 :> g.V().count() 形式运行命令。 此前缀是命令的一部分,在将 Gremlin 控制台与 Azure Cosmos DB 一起使用时非常重要。 省略此前缀将指示控制台在本地执行命令,通常针对一个内存中图表执行。 使用此前缀 :> 则指示控制台执行远程命令,在此示例中针对 Azure Cosmos DB(localhost 仿真器或 Azure 实例)执行。

    很好! 完成设置后,我们开始运行一些控制台命令。

    现在尝试一个简单的 count() 命令。 在控制台的提示符下键入以下命令:

    g.V().count()
    

    创建顶点和边缘

    首先为 Thomas、Mary Kay、Robin、Ben 和 Jack 添加五个人员顶点 。

    输入 (Thomas):

    g.addV('person').property('firstName', 'Thomas').property('lastName', 'Andersen').property('age', 44).property('userid', 1).property('pk', 'pk')
    
    ==>[id:796cdccc-2acd-4e58-a324-91d6f6f5ed6d,label:person,type:vertex,properties:[firstName:[[id:f02a749f-b67c-4016-850e-910242d68953,value:Thomas]],lastName:[[id:f5fa3126-8818-4fda-88b0-9bb55145ce5c,value:Andersen]],age:[[id:f6390f9c-e563-433e-acbf-25627628016e,value:44]],userid:[[id:796cdccc-2acd-4e58-a324-91d6f6f5ed6d|userid,value:1]]]]
    

    输入 (Mary Kay):

    g.addV('person').property('firstName', 'Mary Kay').property('lastName', 'Andersen').property('age', 39).property('userid', 2).property('pk', 'pk')
    
    ==>[id:0ac9be25-a476-4a30-8da8-e79f0119ea5e,label:person,type:vertex,properties:[firstName:[[id:ea0604f8-14ee-4513-a48a-1734a1f28dc0,value:Mary Kay]],lastName:[[id:86d3bba5-fd60-4856-9396-c195ef7d7f4b,value:Andersen]],age:[[id:bc81b78d-30c4-4e03-8f40-50f72eb5f6da,value:39]],userid:[[id:0ac9be25-a476-4a30-8da8-e79f0119ea5e|userid,value:2]]]]
    

    输入 (Robin):

    g.addV('person').property('firstName', 'Robin').property('lastName', 'Wakefield').property('userid', 3).property('pk', 'pk')
    
    ==>[id:8dc14d6a-8683-4a54-8d74-7eef1fb43a3e,label:person,type:vertex,properties:[firstName:[[id:ec65f078-7a43-4cbe-bc06-e50f2640dc4e,value:Robin]],lastName:[[id:a3937d07-0e88-45d3-a442-26fcdfb042ce,value:Wakefield]],userid:[[id:8dc14d6a-8683-4a54-8d74-7eef1fb43a3e|userid,value:3]]]]
    

    输入 (Ben):

    g.addV('person').property('firstName', 'Ben').property('lastName', 'Miller').property('userid', 4).property('pk', 'pk')
    
    ==>[id:ee86b670-4d24-4966-9a39-30529284b66f,label:person,type:vertex,properties:[firstName:[[id:a632469b-30fc-4157-840c-b80260871e9a,value:Ben]],lastName:[[id:4a08d307-0719-47c6-84ae-1b0b06630928,value:Miller]],userid:[[id:ee86b670-4d24-4966-9a39-30529284b66f|userid,value:4]]]]
    

    输入 (Jack):

    g.addV('person').property('firstName', 'Jack').property('lastName', 'Connor').property('userid', 5).property('pk', 'pk')
    
    ==>[id:4c835f2a-ea5b-43bb-9b6b-215488ad8469,label:person,type:vertex,properties:[firstName:[[id:4250824e-4b72-417f-af98-8034aa15559f,value:Jack]],lastName:[[id:44c1d5e1-a831-480a-bf94-5167d133549e,value:Connor]],userid:[[id:4c835f2a-ea5b-43bb-9b6b-215488ad8469|userid,value:5]]]]
    

    接下来,为人员之间的关系添加边缘。

    输入 (Thomas-> Mary Kay):

    g.V().hasLabel('person').has('firstName', 'Thomas').addE('knows').to(g.V().hasLabel('person').has('firstName', 'Mary Kay'))
    
    ==>[id:c12bf9fb-96a1-4cb7-a3f8-431e196e702f,label:knows,type:edge,inVLabel:person,outVLabel:person,inV:0d1fa428-780c-49a5-bd3a-a68d96391d5c,outV:1ce821c6-aa3d-4170-a0b7-d14d2a4d18c3]
    

    输入 (Thomas-> Robin):

    g.V().hasLabel('person').has('firstName', 'Thomas').addE('knows').to(g.V().hasLabel('person').has('firstName', 'Robin'))
    
    ==>[id:58319bdd-1d3e-4f17-a106-0ddf18719d15,label:knows,type:edge,inVLabel:person,outVLabel:person,inV:3e324073-ccfc-4ae1-8675-d450858ca116,outV:1ce821c6-aa3d-4170-a0b7-d14d2a4d18c3]
    

    输入 (Robin -> Ben):

    g.V().hasLabel('person').has('firstName', 'Robin').addE('knows').to(g.V().hasLabel('person').has('firstName', 'Ben'))
    
    ==>[id:889c4d3c-549e-4d35-bc21-a3d1bfa11e00,label:knows,type:edge,inVLabel:person,outVLabel:person,inV:40fd641d-546e-412a-abcc-58fe53891aab,outV:3e324073-ccfc-4ae1-8675-d450858ca116]
    

    使用新年龄 45 更新 Thomas 顶点。

    g.V().hasLabel('person').has('firstName', 'Thomas').property('age', 45)
    
    ==>[id:ae36f938-210e-445a-92df-519f2b64c8ec,label:person,type:vertex,properties:[firstName:[[id:872090b6-6a77-456a-9a55-a59141d4ebc2,value:Thomas]],lastName:[[id:7ee7a39a-a414-4127-89b4-870bc4ef99f3,value:Andersen]],age:[[id:a2a75d5a-ae70-4095-806d-a35abcbfe71d,value:45]]]]
    

    现在,我们针对图形运行各种查询。

    首先,我们尝试结合筛选器运行一个查询,以返回年龄超过 40 岁的人员。

    输入(筛选器查询):

    g.V().hasLabel('person').has('age', gt(40))
    
    ==>[id:ae36f938-210e-445a-92df-519f2b64c8ec,label:person,type:vertex,properties:[firstName:[[id:872090b6-6a77-456a-9a55-a59141d4ebc2,value:Thomas]],lastName:[[id:7ee7a39a-a414-4127-89b4-870bc4ef99f3,value:Andersen]],age:[[id:a2a75d5a-ae70-4095-806d-a35abcbfe71d,value:45]]]]
    

    接下来,投影年龄超过 40 岁的人员的名字。

    输入(筛选器 + 投影查询):

    g.V().hasLabel('person').has('age', gt(40)).values('firstName')
    
    ==>Thomas
    

    我们遍历图形,返回 Thomas 的所有朋友。

    输入(Thomas 的朋友):

    g.V().hasLabel('person').has('firstName', 'Thomas').outE('knows').inV().hasLabel('person')
    
    ==>[id:f04bc00b-cb56-46c4-a3bb-a5870c42f7ff,label:person,type:vertex,properties:[firstName:[[id:14feedec-b070-444e-b544-62be15c7167c,value:Mary Kay]],lastName:[[id:107ab421-7208-45d4-b969-bbc54481992a,value:Andersen]],age:[[id:4b08d6e4-58f5-45df-8e69-6b790b692e0a,value:39]]]]
    ==>[id:91605c63-4988-4b60-9a30-5144719ae326,label:person,type:vertex,properties:[firstName:[[id:f760e0e6-652a-481a-92b0-1767d9bf372e,value:Robin]],lastName:[[id:352a4caa-bad6-47e3-a7dc-90ff342cf870,value:Wakefield]]]]
    

    接下来,获取下一个顶点层。 遍历图形,返回 Thomas 的朋友的所有朋友。

    输入(Thomas 的朋友的朋友):

    g.V().hasLabel('person').has('firstName', 'Thomas').outE('knows').inV().hasLabel('person').outE('knows').inV().hasLabel('person')
    
    ==>[id:a801a0cb-ee85-44ee-a502-271685ef212e,label:person,type:vertex,properties:[firstName:[[id:b9489902-d29a-4673-8c09-c2b3fe7f8b94,value:Ben]],lastName:[[id:e084f933-9a4b-4dbc-8273-f0171265cf1d,value:Miller]]]]
    

    现在,我们从图形数据库中删除某个顶点。

    输入(删除 Jack 顶点):

    g.V().hasLabel('person').has('firstName', 'Jack').drop()
    

    最后,我们清除所有顶点和边缘的数据库。

    g.E().drop()
    g.V().drop()
    

    祝贺你! 你已完成“Azure Cosmos DB:Gremlin API”教程!

    在 Azure 门户中查看 SLA

    Azure 门户可监视 Azure Cosmos DB 帐户吞吐量、存储、可用性、延迟和一致性。 与 Azure Cosmos DB 服务级别协议 (SLA) 关联的指标的图表显示与实际性能相比的 SLA 值。 此套指标使得监视 SLA 十分透明。

    若要查看指标和 SLA,请执行以下操作:

  • 请在 Azure Cosmos DB 帐户的导航菜单中选择“指标”。

  • 选择一个选项卡,如“延迟”,然后选择右侧的时间范围。 比较图表上的“实际”和“SLA”线。

  • 查看其他选项卡上的指标。

    执行完应用和 Azure Cosmos DB 帐户的操作以后,可以删除所创建的 Azure 资源,以免产生更多费用。 若要删除资源,请执行以下操作:

  • 在 Azure 门户的“搜索”栏中,搜索并选择“资源组” 。

  • 从列表中选择为本快速入门创建的资源组。

  • 在资源组“概览”页上,选择“删除资源组” 。

  • 在下一窗口中输入要删除的资源组的名称,然后选择“删除” 。

    本快速入门教程已介绍如何创建 Azure Cosmos DB 帐户、使用数据资源管理器创建图形、创建顶点和边缘,以及使用 Gremlin 控制台遍历图形。 现可使用 Gremlin 构建更复杂的查询,实现功能强大的图形遍历逻辑。

    使用 Gremlin 查询

  •