gdbots/ncr

Node Content Repository for php.


README

Node Content Repository for php. 使用此库假设您已经使用 Pbjc 创建和编译了自己的 pbj 类,并正在使用 gdbots/schemas 中的 "gdbots:ncr:mixin:*" 混合。

如果您的项目使用 Symfony,请使用 gdbots/ncr-bundle-php 来简化集成。

节点和边

一个 节点或顶点 是系统中的一个 名词/实体。文章、推文、视频、人、地点、订单、产品等。边是这些事物之间的 关系,如“朋友”、“标记为”、“与...结婚”、“由...发布”等。

此库不提供图形数据库实现。它关注于持久化和检索节点和边。图遍历仍需要由另一个库提供。建议将数据从 Ncr(或像 GraphQL 一样分层)复制或投影到适合此目的的东西中(例如 Neo4j、Titan ElasticSearch)。

NodeRef

NodeRef 是一个节点/顶点的合格标识符。它比 MessageRef 简洁,因为它隐含地表示节点标签必须在给定的供应商命名空间内是唯一的,因此可以以更紧凑的方式表示。

NodeRef 格式: vendor:label:id 其中 "vendor:label" 部分是一个 SchemaQName

示例

acme:article:41e4532f-2f58-4b9d-afc8-e9c2cbcb4aba twitter:tweet:789234931599835136 youtube:video:EG0wQRsXLi4

节点实际上没有 node_ref 字段,它们有一个 _id 字段。NodeRef 是通过取节点的模式 SchemaQName 和其 _id 得到的。NodeRef 是一个不可变值对象,在许多地方使用而无需实际拥有节点实例。

Ncr

Ncr 是负责节点持久化的服务。它有意限制为基本键/值存储操作(例如 put/get/按索引查找),以确保底层实现可以轻松更换或装饰(例如缓存层)。

可用的存储库实现

  • DynamoDb
  • Psr6 (提供 Redis、File、Memcached、Doctrine 等)
  • InMemory

查看 Gdbots\Ncr\Ncr 接口以获取可用的方法。

Ncr::findNodeRefs

Ncr 是一个简单的键/值存储,这意味着查询仅限于项的 ID 或二级索引。二级索引的示例可以是用户的电子邮件或用户名、文章的 slug 或书籍的 isbn。

使用 IndexQueryfindNodeRefs,这些查询与二级索引匹配。

使用 IndexQuery 的示例

$query = IndexQueryBuilder::create(SchemaQName::fromString('acme:user'), 'email', 'homer@simpson.com')
    ->setCount(1)
    ->build();
$result = $this->ncr->findNodeRefs($query);
if (!$result->count()) {
    throw new NodeNotFound('Unable to find homer.');
}

$node = $this->ncr->getNode($result->getNodeRefs()[0]);

并非所有存储引擎都可以在二级索引上强制唯一性,因此接口也不能做出这种假设。因此,findNodeRefs 可能会返回多个值。处理这个问题取决于您的应用程序逻辑。

Ncr::pipeNodes

从 Ncr 获取数据应该是死简单的,毕竞只是 JSON。使用 pipeNodespipeNodeRefs 方法导出数据。gdbots/ncr-bundle-php 提供了利用此功能的控制台命令,用于导出和重新索引节点。

使用 pipeNodes 导出节点

foreach ($ncr->pipeNodes(SchemaQName::fromString('acme:article')) as $node) {
    echo json_encode($node) . PHP_EOL;
}

NcrCache

NcrCache 是一个一级缓存,它**仅**由当前请求看到和使用。它用于缓存从获取节点请求返回的所有节点。在处理 Pbjx 请求或 Ncr 在当前进程中运行并使用 MemoizingNcr 时,使用此缓存。

当需要一致性结果时,不应使用此缓存。

NcrCache 不是一个标识映射Ncr 不是一个 ORM。在某些情况下,您可能会得到相同的对象,但这并不保证,因此不要这样做

$nodeRef = NodeRef::fromString('acme:article:123');
$cache->getNode($nodeRef) !== $cache->getNode($nodeRef);

如果需要检查相等性,请使用消息接口

$node1 = $cache->getNode($nodeRef);
$node2 = $cache->getNode($nodeRef);
$node->equals($node2); // returns true if their data is the same

NcrLazyLoader

NcrCache 和其他请求拦截器使用此服务批量加载节点,仅当它们被请求时。例如,当加载文章时,您可能想获取作者或相关项目,但并非总是如此。与其在文章加载中强制逻辑存在,不如由其他东西来管理。

延迟加载通常是特定于应用程序的,因此此库提供了一些工具来简化这个过程。

示例延迟加载

public function onSearchNodesResponse(ResponseCreatedEvent $pbjxEvent): void
{
    $response = $pbjxEvent->getResponse();
    if (!$response->has('nodes')) {
        return;
    }

    // for all nodes in this search response, mark the creator
    // and updater for lazy load.  if they get requested at some point
    // in the current request, it will be batched for optimal performance
    $this->lazyLoader->addEmbeddedNodeRefs($response->get('nodes'), [
        'creator_ref' => 'acme:user',
        'updater_ref' => 'acme:user',
    ]);
}

NcrSearch

Ncr 提供了节点可靠存储和检索。在大多数情况下,NcrSearch 是一个单独的存储提供者。例如,DynamoDb 用于 Ncr,ElasticSearch 用于 NcrSearch。事实上,我们目前唯一的实现是 ElasticSearch。

当使用 gdbots/ncr-bundle-php 时,您可以通过简单的配置选项启用索引。该套餐还提供了一个重新索引控制台命令。

通常在请求处理器中执行节点搜索。以下是一个搜索节点的示例

public function handleRequest(Message $request, Pbjx $pbjx): Message
{
    $parsedQuery = ParsedQuery::fromArray(json_decode($request->get('parsed_query_json', '{}'), true));

    $response = SearchUsersResponseV1::create();
    $this->ncrSearch->searchNodes(
        $request,
        $parsedQuery,
        $response,
        [SchemaQName::fromString('acme:user')]
    );

    return $response;
}