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
,失败时为 false
。saveMany
可以有第二个参数,其选项与 save()
接受的选项相同。
检索到文档后,您可以将其删除
$doc = $this->Articles->get($id);
$this->Articles->delete($doc);
您还可以删除与特定条件匹配的文档
$this->Articles->deleteAll(['user.name' => 'bob']);
通过定义嵌入文档,您可以将实体类附加到文档中的特定属性路径。这允许您为父文档内的文档提供自定义行为。例如,您可能希望嵌入到文章中的评论具有特定于应用程序的方法。可以使用 embedOne
和 embedMany
定义嵌入文档
// 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'];