进一步查询机制

隐式(或自动提交)事务

这是运行 Cypher 查询最基本和有限的形式。驱动程序不会自动重试隐式事务,而对于通过 Driver.executeQuery()托管事务 运行的查询则会重试。隐式事务仅应在其他驱动程序查询接口不适用或用于快速原型开发时使用。

您可以使用方法 Session.run() 运行隐式事务,该方法返回一个 Result 对象。

let session = driver.session({database: 'neo4j'})
try {
  const result = await session.run(
    'MERGE (a:Person {name: $name})',
    { name: 'Alice'}
  )
} finally {
  await session.close()
}

由于驱动程序无法判断 session.run() 调用中的查询需要数据库的读取会话还是写入会话,它默认为写入。如果您的隐式事务只包含读取查询,通过在创建会话时设置关键字参数 defaultAccessMode=neo4j.session.READ 使驱动程序知晓,可以获得性能提升。

隐式事务是唯一可用于 CALL { …​ } IN TRANSACTIONS 查询的事务.
您也可以使用 响应式会话 运行隐式事务。

导入 CSV 文件

使用 Session.run() 最常见的用例是使用 LOAD CSV Cypher 子句将大型 CSV 文件导入数据库,并防止因事务大小而导致的超时错误。

将 CSV 数据导入 Neo4j 数据库
let session = driver.session({database: 'neo4j'})
try {
  let result = await session.run(`
    LOAD CSV FROM 'https://data.neo4j.com/bands/artists.csv' AS line
    CALL {
        WITH line
        MERGE (:Artist {name: line[1], age: toInteger(line[2])})
    } IN TRANSACTIONS OF 2 ROWS
  `)
  console.log(result.summary.counters.updates())
} finally {
  await session.close()
}
虽然 LOAD CSV 提供了便利,但将 CSV 文件的解析推迟到您的 JavaScript 应用程序并避免使用 LOAD CSV 并没有什么不妥。事实上,将解析逻辑移到应用程序可以为您提供对导入过程的更多控制。有关高效批量数据插入,请参见 性能 → 批量数据创建

有关更多信息,请参见 Cypher → 子句 → Load CSV

事务配置

您可以通过为 session.run() 提供类型为 TransactionConfig 的可选第三个参数,对隐式事务进行进一步控制。此配置允许指定查询超时时间并将元数据附加到事务。有关更多信息,请参见 事务 — 事务配置

let session = driver.session({database: 'neo4j'})
let result = await session.run(
  'MATCH (a:Person) RETURN count(a) AS people',
  {},  // query parameters
  { timeout: 5000, metadata: {'appName': 'peopleTracker'} }  // transactionConfig
)

属性键、关系类型和标签中的动态值

通常,您不应将参数直接拼接到查询中,而应使用 查询参数。然而,在某些情况下,您的查询结构可能会阻止在所有部分中使用参数。事实上,尽管参数可以用于字面量、表达式以及节点和关系 ID,但它们不能用于以下构造:

  • 属性键,因此 MATCH (n) WHERE n.$param = 'something' 是无效的;

  • 关系类型,因此 MATCH (n)-[:$param]→(m) 是无效的;

  • 标签,因此 MATCH (n:$param) 是无效的。

对于这些查询,您被迫使用字符串拼接。为了防止 Cypher 注入,您应该将动态值用反引号括起来并自行转义。请注意,Cypher 处理 Unicode,因此也要注意 Unicode 字面量 \u0060

在拼接前手动转义动态标签
let dangerousLabel = 'Special Person\\u0060'
// convert \u0060 to literal backtick, then escape backticks
let escapedLabel = dangerousLabel.replace(/\\u0060/g, '`').replace(/`/g, '``')

let result = await driver.executeQuery(
  'MATCH (p:`' + escapedLabel + '`) RETURN p.name',
  {},
  {database: 'neo4j'}
)
console.log(`Executed query: ${result.summary.query.text}`)

另一种避免字符串拼接的变通方法是使用 APOC 过程 apoc.merge.node。它支持动态标签和属性键,但仅限于节点合并。

使用 apoc.merge.node 创建具有动态标签/属性键的节点
let propertyKey = 'name'
let label = 'Person'
let result = await driver.executeQuery(
  'CALL apoc.merge.node($labels, $properties)',
  {labels: [label], properties: {property_key: 'Alice'}},
  {database: 'neo4j'}
)
如果您在 Docker 中运行 Neo4j,APOC 需要在启动容器时启用。请参见 APOC → 安装 → Docker

日志记录

创建 Driver 实例时,您可以选择性地指定其日志记录配置。

日志记录默认是关闭的。要启用它,在初始化驱动程序时指定 logging 选项。作为值,使用函数 neo4j.logging.console(),它会将日志输出到控制台并接受一个可选参数 level。日志级别可以是 errorwarninfodebug。启用一个级别会自动启用所有更高优先级的级别,其默认级别为 info

创建一个日志级别为 debug 并输出到控制台的驱动程序
neo4j.driver(
  URI,
  neo4j.auth.basic(USER, PASSWORD),
  {  // driver config
    logging: neo4j.logging.console('debug')
  }
)
驱动程序连接后的日志输出示例
1681215847749 INFO Routing driver 0 created for server address localhost:7687
1681215847765 INFO Routing table is stale for database: "neo4j" and access mode: "WRITE": RoutingTable[database=neo4j, expirationTime=0, currentTime=1681215847765, routers=[], readers=[], writers=[]]
1681215847773 DEBUG Connection [0][] created towards localhost:7687(127.0.0.1)
1681215847773 DEBUG Connection [0][] C: HELLO {user_agent: 'neo4j-javascript/5.3.0', ...}
1681215847778 DEBUG Connection [0][] S: SUCCESS {"signature":112,"fields":[{"server":"Neo4j/5.8.0","connection_id":"bolt-1782","hints":{"connection.recv_timeout_seconds":{"low":120,"high":0}}}]}
1681215847778 DEBUG Connection [0][bolt-1782] created for the pool localhost:7687
1681215847778 DEBUG Connection [0][bolt-1782] acquired from the pool localhost:7687
1681215847779 DEBUG Connection [0][bolt-1782] C: ROUTE {"address":"localhost:7687"} [] {"db":"neo4j"}
1681215847781 DEBUG Connection [0][bolt-1782] S: SUCCESS {"signature":112,"fields":[{"rt":{"servers":[{"addresses":["localhost:7687"],"role":"WRITE"},{"addresses":["localhost:7687"],"role":"READ"},{"addresses":["localhost:7687"],"role":"ROUTE"}],"ttl":{"low":300,"high":0},"db":"neo4j"}}]}

您还可以指定一个自定义日志函数,例如将日志记录到文件。在这种情况下,logging 选项需要两个属性:

  • level:可以是 errorwarninfodebug。启用一个级别会自动启用所有更高优先级的级别。默认为 info

  • logger:一个在需要记录消息时调用的函数。它接受 level, message 作为输入。

创建一个日志级别为 error 并输出到控制台的驱动程序
neo4j.driver(
  URI,
  neo4j.auth.basic(USER, PASSWORD),
  {  // driver config
    logging: {
      level: 'error',
      logger: (level, message) => console.log(level + ' ' + message)
    }
  }
)

您可以在 API 文档 中找到更多关于日志记录的信息。

术语表

LTS (长期支持)

长期支持 (Long Term Support) 版本是指保证在数年内获得支持的版本。Neo4j 4.4 是 LTS 版本,Neo4j 5 也将拥有一个 LTS 版本。

Aura

Aura 是 Neo4j 的全托管云服务。它提供免费和付费计划。

Cypher

Cypher 是 Neo4j 的图查询语言,用于从数据库中检索数据。它类似于 SQL,但专用于图。

APOC

Awesome Procedures On Cypher (APOC) 是一个包含许多无法在 Cypher 本身轻松表达的函数的库。

Bolt

Bolt 是 Neo4j 实例和驱动程序之间交互使用的协议。它默认监听端口 7687。

ACID

原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)(ACID) 是保证数据库事务可靠处理的属性。符合 ACID 的 DBMS 确保数据库中的数据即使在发生故障时也能保持准确和一致。

最终一致性

如果数据库保证所有集群成员在某个时间点将存储数据的最新版本,则该数据库是最终一致的。

因果一致性

如果集群的每个成员都以相同的顺序看到读写查询,则数据库是因果一致的。这比最终一致性更强。

NULL

空标记不是一种类型,而是表示值缺失的占位符。有关更多信息,请参见 Cypher → 使用 null

事务

事务是一个工作单元,要么整体提交,要么在失败时回滚。例如银行转账:它涉及多个步骤,但它们必须全部成功或被撤销,以避免资金从一个账户中扣除但未添加到另一个账户。

背压

背压是阻碍数据流动的力。它确保客户端不会被超出其处理能力的数据量所淹没。

© . All rights reserved.