ElasticSearch

ElasticSearch 插件在 elasticsearch 之上提供类似 ORM 的抽象。该插件提供了使测试、索引文档和搜索索引变得更容易的功能。

安装

要安装 ElasticSearch 插件,可以使用 composer。从应用程序的 ROOT 目录(composer.json 文件所在位置)运行以下命令

php composer.phar require cakephp/elastic-search "^4.0"

您需要在应用程序的 src/Application.php 文件中添加以下行

$this->addPlugin('Cake/ElasticSearch');

此外,您需要在 config/app.php 文件中配置“elastic”数据源连接。示例配置如下

// in config/app.php
'Datasources' => [
    // other datasources
    'elastic' => [
        'className' => 'Cake\ElasticSearch\Datasource\Connection',
        'driver' => 'Cake\ElasticSearch\Datasource\Connection',
        'host' => '127.0.0.1',
        'port' => 9200,
        'index' => 'my_apps_index',
    ],
]

如果您的端点需要 https,请使用

'port' => 443,
'transport' => 'https'

否则您可能会从 elasticsearch 服务器收到 400 响应。

概述

ElasticSearch 插件使与 elasticsearch 索引的交互变得更容易,并提供类似于 ORM 的接口。要开始,您应该创建一个 Index 对象。Index 对象是 elasticsearch 中的“Repository”或类似表格的类

// in src/Model/Type/ArticlesIndex.php
namespace App\Model\Index;

use Cake\ElasticSearch\Index;

class ArticlesIndex extends Index
{
}

然后,您可以在控制器中使用索引类

public function beforeFilter(Event $event)
{
    parent::beforeFilter($event);
    // Load the Index using the 'Elastic' provider.
    $this->loadModel('Articles', 'Elastic');
}

public function add()
{
    $article = $this->Articles->newEntity();
    if ($this->request->is('post')) {
        $article = $this->Articles->patchEntity($article, $this->request->getData());
        if ($this->Articles->save($article)) {
            $this->Flash->success('It saved');
        }
    }
    $this->set(compact('article'));
}

我们还需要为索引的 文章 创建一个基本视图

// in src/Template/Articles/add.ctp
<?= $this->Form->create($article) ?>
<?= $this->Form->control('title') ?>
<?= $this->Form->control('body') ?>
<?= $this->Form->button('Save') ?>
<?= $this->Form->end() ?>

现在您应该能够提交表单并向 elasticsearch 添加新文档。

文档对象

与 ORM 类似,Elasticsearch ODM 使用类似 ORM 的类。您应该从 Cake\ElasticSearch\Document 继承的基类。文档类位于应用程序或插件的 Model\Document 命名空间中

namespace App\Model\Document;

use Cake\ElasticSearch\Document;

class Article extends Document
{
}

除了使文档与来自 elasticsearch 的数据一起工作的构造函数逻辑之外,Document 提供的接口和功能与 实体 中的一样

搜索索引文档

索引了一些文档后,您可能想要搜索它们。ElasticSearch 插件提供了一个查询构建器,它允许您构建搜索查询

$query = $this->Articles->find()
    ->where([
        'title' => 'special',
        'or' => [
            'tags in' => ['cake', 'php'],
            'tags not in' => ['c#', 'java']
        ]
    ]);

foreach ($query as $article) {
    echo $article->title;
}

您可以使用 QueryBuilder 添加过滤条件

$query->where(function ($builder) {
    return $builder->and(
        $builder->gt('views', 99),
        $builder->term('author.name', 'sally')
    );
});

QueryBuilder 源代码 包含完整的方法列表,以及许多常用方法的示例。

验证数据和使用应用程序规则

与 ORM 类似,ElasticSearch 插件允许您在编组文档时验证数据。验证请求数据和应用应用程序规则的工作方式与关系 ORM 相同。有关更多信息,请参阅 验证请求数据应用程序规则 部分。

保存新文档

准备好将一些数据索引到 elasticsearch 中时,您首先需要将数据转换为可以索引的 Document

$article = $this->Articles->newEntity($data);
if ($this->Articles->save($article)) {
    // Document was indexed
}

编组文档时,可以使用 associated 键指定要编组的嵌入文档

$article = $this->Articles->newEntity($data, ['associated' => ['Comments']]);

保存文档将触发以下事件

  • Model.beforeSave - 在保存文档之前触发。您可以通过停止此事件来阻止保存操作。

  • Model.buildRules - 第一次构建规则检查器时触发。

  • Model.afterSave - 在保存文档后触发。

注意

嵌入文档没有事件,因为父文档及其所有嵌入文档作为一个操作保存。

更新现有文档

当您需要重新索引数据时,可以修补现有实体并重新保存它们

$query = $this->Articles->find()->where(['user.name' => 'jill']);
foreach ($query as $doc) {
    $doc->set($newProperties);
    $this->Articles->save($doc);
}

此外,Elasticsearch refresh 请求可以通过在 $options 参数中传递 'refresh' => true 来触发。刷新使最近对一个或多个索引执行的操作可供搜索。

$this->Articles->save($article, ['refresh' => true]);

保存多个文档

使用此方法,您可以批量保存多个文档

$result = $this->Articles->saveMany($documents);

这里 $documents 是一个文档数组。成功时结果将为 true,失败时为 falsesaveMany 可以有第二个参数,其选项与 save() 接受的选项相同。

删除文档

检索到文档后,您可以将其删除

$doc = $this->Articles->get($id);
$this->Articles->delete($doc);

您还可以删除与特定条件匹配的文档

$this->Articles->deleteAll(['user.name' => 'bob']);

嵌入文档

通过定义嵌入文档,您可以将实体类附加到文档中的特定属性路径。这允许您为父文档内的文档提供自定义行为。例如,您可能希望嵌入到文章中的评论具有特定于应用程序的方法。可以使用 embedOneembedMany 定义嵌入文档

// in src/Model/Index/ArticlesIndex.php
namespace App\Model\Index;

use Cake\ElasticSearch\Index;

class ArticlesIndex extends Index
{
    public function initialize()
    {
        $this->embedOne('User');
        $this->embedMany('Comments', [
            'entityClass' => 'MyComment'
        ]);
    }
}

以上操作将在 Article 文档上创建两个嵌入文档。User 嵌入将 user 属性转换为 App\Model\Document\User 的实例。要使 Comments 嵌入使用与属性名称不匹配的类名,可以使用 entityClass 选项配置自定义类名。

设置好嵌入文档后,find()get() 的结果将返回带有正确嵌入文档类的对象

$article = $this->Articles->get($id);
// Instance of App\Model\Document\User
$article->user;

// Array of App\Model\Document\Comment instances
$article->comments;

配置连接

默认情况下,所有索引实例都使用 elastic 连接。如果您的应用程序使用多个连接,则需要配置哪个索引使用哪个连接。这是 defaultConnectionName() 方法

namespace App\Model\Index;

use Cake\ElasticSearch\Index;

class ArticlesIndex extends Index
{
    public static function defaultConnectionName() {
        return 'replica_db';
    }
}

注意

defaultConnectionName() 方法**必须**是静态的。

获取索引实例

与 ORM 类似,ElasticSearch 插件提供了一个工厂/注册表,用于获取 Index 实例

use Cake\ElasticSearch\IndexRegistry;

$articles = IndexRegistry::get('Articles');

刷新注册表

在测试用例中,您可能需要刷新注册表。当您使用模拟对象或修改索引的依赖项时,这样做通常很有用。

IndexRegistry::flush();

测试夹具

ElasticSearch 插件提供了无缝的测试套件集成。就像数据库夹具一样,您可以创建测试模式和夹具数据 elasticsearch。与数据库夹具非常相似,我们在应用程序的 tests/bootstrap.php 中加载我们的 Elasticsearch 映射。

// In tests/bootstrap.php
use Cake\Elasticsearch\TestSuite\Fixture\MappingGenerator;

$generator = new MappingGenerator('tests/mappings.php', 'test_elastic');
$generator->reload();

以上操作将在 tests/mapping.php 中定义的索引和映射,并将它们插入到 test_elastic 连接中。您在 mappings.php 中的映射应该返回要创建的映射列表。

// in tests/mappings.php
return [
    [
        // The name of the index and mapping.
        'name' => 'articles',
        // The schema for the mapping.
        'mapping' => [
            'id' => ['type' => 'integer'],
            'title' => ['type' => 'text'],
            'user_id' => ['type' => 'integer'],
            'body' => ['type' => 'text'],
            'created' => ['type' => 'date'],
        ],
        // Additional index settings.
        'settings' => [
            'number_of_shards' => 2,
            'number_of_routing_shards' => 2,
        ],
    ],
    // ...
];

映射使用 原生 elasticsearch 映射格式。您可以安全地省略类型名称和顶层 properties 键。加载完映射后,我们可以使用以下代码定义一个测试夹具,用于我们的文章索引。

namespace App\Test\Fixture;

use Cake\ElasticSearch\TestSuite\TestFixture;

/**
 * Articles fixture
 */
class ArticlesFixture extends TestFixture
{
    /**
     * The table/index for this fixture.
     *
     * @var string
     */
    public $table = 'articles';

    public $records = [
        [
            'user' => [
                'username' => 'billy'
            ],
            'title' => 'First Post',
            'body' => 'Some content'
        ]
    ];
}

在版本 3.4.0 中更改:在 CakePHP 4.3.0 之前,模式是在每个夹具的 $schema 属性中定义的。

创建夹具后,您可以在测试用例中通过将它们包含在测试的 fixtures 属性中来使用它们。

public $fixtures = ['app.Articles'];