hellopablo / related-content
一个用于分析应用程序中的对象并查找相关内容的框架。
Requires
- php: >8.0
Requires (Dev)
- phpstan/phpstan: ^0.12.19
- phpunit/phpunit: ^8.5.4
Suggests
- ext-pdo: Install the PDO extension to use the MySQL Store
README
这是一个简单的PHP框架,用于分析应用程序中的对象,并提供查找相关内容的API。使用您自己的分析器从对象中提取关系节点,以便找到具有类似节点的其他对象。
例如,您可能有 Article
和 Blog
对象,它们都具有 categories
,此框架允许您轻松定义两种数据类型(提取分类节点)的分析器,从而使您能够找到类似分类的项目。
目录
安装
使用Composer安装
composer require hellopablo/related-content
该包中的所有类都在命名空间 HelloPablo\RelatedContent
下,并且可以使用PSR-4自动加载。
分析器
此框架的一个关键概念是分析器。分析器是实现 Interfaces\Analyser
接口的类。它们的目的是对您的对象进行检查并提取可用于索引的数据点(节点)。
预期您应用程序中的每种不同类型的数据都有自己的分析器,即使它们具有相似的结构也是如此。在内部,引擎使用分析器作为区分数据类型的键。
🧑💻 理解分析器是由您的应用程序提供的非常重要。框架对您的数据看起来如何没有意见,也不会推断任何关系 - 提取关系数据取决于您。
关系节点
关系节点是描述正在索引的对象的一部分的单个数据点。节点实现 Interfaces\Relation
接口,并应定义一个 type
和一个 value
。通常,type
是描述节点的应用程序提供的字符串(例如 CATEGORY
、TOPIC
或 AUTHOR
),而 value
是 type
的ID或其他标识符。
🙋 框架提供了一个
Relation\Node
类,您可以在应用程序的分析器中使用它。
示例
对于看起来像这样的对象
{ "id": 1, "label": "My Article", "body": "Nullam id dolor id nibh ultricies ... auctor fringilla.", "categories": [1, 2, 3], "topics": [5, 6, 7] }
我们可能希望将 categories
和 topics
ID 描述为关系节点。在这个示例中,分析器可能看起来像这样
namespace App\RelatedContent\Analysers; use HelloPablo\RelatedContent\Interfaces; use HelloPablo\RelatedContent\Relation; class Article implements Interfaces\Analsyer { /** * Analyses an item and returns an array of Interfaces\Relation * * @param object $item The item to analyse * * @return Relation\Node[] */ public function analyse(object $item): array { $nodes = []; foreach ($item->categories as $categoryId) { $nodes[] = new Relation\Node('CATEGORY', $categoryId); } foreach ($item->topics as $topicId) { $nodes[] = new Relation\Node('TOPIC', $topicId); } return $nodes; } /** * Returns the item's unique identifier * * @param object $item * * @return int */ public function getId(object $item) { return $item->id; } }
其他分析器(例如,对于博客文章)也可能返回 CATEGORY
和 TOPIC
节点。考虑的是节点类型和值的重叠,这被认为是关系。
引擎
引擎是您的应用程序将与相关内容存储交互的方式(主要是)。它简化了从 数据存储 读取和写入,以及使用 分析器 索引内容提供接口。
可以通过 Factory
类检索引擎的新实例,您必须传递要使用的 数据存储 的实例。
使用 MySQL 数据存储 的示例
use HelloPablo\RelatedContent; $store = new RelatedContent\Store\MySQL([ 'user' => 'mysql_user', 'password' => 'mysql_password', 'database' => 'mysql_database', ]); /** @var Engine $engine */ $engine = RelatedContent\Factory::build($store);
索引
索引是将对象进行分析并将其关系节点保存到数据存储的过程。可以使用引擎的 index(object $item, Interfaces\Analyser $analyser): self
方法实现。
use App\RelatedContent\Analysers; /** * The item we wish to index. This would typically be retrieved using a * model, an ORM, or some other app-orientated struct. */ $item = (object) [ 'id' => 1, 'label' => 'My Article', 'body' => 'Nullam id dolor id nibh ultricies ... auctor fringilla.', 'categories' => [1, 2, 3], 'topics' => [5, 6, 7] ]; $analyser = new Analysers\Article(); $engine->index($item, $analyser);
💁 索引项目将删除该项目之前保留的所有数据。
查询
查询是本库的核心功能——通过提供源项目(及其分析器),引擎可以找到匹配的项目并返回命中结果,按分数排序(最相关者排在前面)。您的应用程序可以使用这些结果来获取源项目并进行进一步逻辑处理。
查询通过引擎的query(): Query\Hit[]
方法实现。此方法接受四个参数
- 源项目,即我们想要查找相关内容的项。
- 源项目的分析器,即用于索引该项目的分析器。
- 任何要限制结果的数据类型,以分析器数组的形式传递,即我们只想看到与我们的源
Article
相关的Blog
结果。 - 要返回的结果数量。
使用示例最好地解释了查询方法。假设此系统存储有关两种数据类型的关联数据:Article
和Blog
,我们可能有以下分析器
use App\RelatedContent\Analysers; $articleAnalyser = new Analysers\Article(); $blogAnalyser = new Analysers\Blog();
这些分析器分别为其对应的数据类型提取category
数据。有了我们的源Article
项目,我们可以找到相关的Article
和Blog
内容如下
/** * The item which was indexed; at minimum you need the analyser * to be able to acertain the item's ID. */ $articleItem = (object) [ 'id' => 1, ]; $results = $engine->query( $articleItem, $articleAnalyser );
$results
数组将是一个包含Query\Hit
对象的数组。这些对象提供三种方法
getAnalyser(): Interfaces\Analyser
,它将返回用于索引项目的分析器实例。getId(): string|int
,它将返回索引项的ID。getScore(): int
,它将返回命中的分数。
如果我们想限制结果只包含某些数据类型,那么我们将作为第三个参数传递我们想要限制的分析器实例数组,此外,我们可以通过传递一个整数作为第四个参数来限制结果数量
/** * The item which was indexed; at minimum you need the analyser * to be able to acertain the item's ID. */ $articleItem = (object) [ 'id' => 1, ]; /** * Return up to 3 related blog posts for our article. */ $results = $engine->query( $articleItem, $articleAnalyser, [ $blogAnalyser ], 3 );
读取
您可以使用引擎的read(object $item, Interfaces\Analyser $analyser): Interfaces\Relation[]
方法读取有关特定项存储的所有数据
use App\RelatedContent\Analysers; /** * The item which was indexed; at minimum you need the analyser * to be able to acertain the item's ID. */ $item = (object) [ 'id' => 1, ]; $analyser = new Analysers\Article(); $relations = $engine->read($item, $analyser);
删除
要删除有关项的所有数据,请使用引擎的delete(object $item, Interfaces\Analyser $analyser): self
方法
use App\RelatedContent\Analysers; /** * The item which was indexed; at minimum you need the analyser * to be able to acertain the item's ID. */ $item = (object) [ 'id' => 1, ]; $analyser = new Analysers\Article(); $relations = $engine->delete($item, $analyser);
转储
如果您需要转储数据存储的全部内容,您可以使用引擎的dump(): array
方法。它将返回存储在数据存储中的所有关系的数组。
$items = $engine->dump();
清空
要彻底清空数据存储,您可以使用引擎的empty(): self
方法。此操作不可逆。
$engine->empty();
数据存储
数据存储是引擎保存索引数据的地方。您可以使用您喜欢的任何数据存储;所有适配器都必须实现Interfaces\Store
接口。该包提供了两个默认存储
临时
Store\Ephemeral(array $config = [])
Ephemeral存储是一个内存中的存储。它使用一个类数组,任何数据都不打算在类实例的生命周期之外持久化(当然,除非您手动序列化对象)。
它主要用于测试套件,但在需要时也可作为一等公民使用。此存储的一个示例用途可能是用于长时间运行的脚本,该脚本构建关系模型并缓存结果,实际的数据存储不需要持久化。
配置
此存储接受配置数组中的以下键
MySQL
Store\MySQL(array $config = [])
此MySQL存储允许您使用MySQL表作为关系数据的持久化数据存储。它利用PHP提供的\PDO
类。
配置
此存储接受配置数组中的以下键