O plugin ElasticSearch disponibiliza uma abstração semelhante a do ORM para conversar com o elasticsearch. O plugin disponibiliza recursos que tornam testes, indexação de documentos e busca por seus índices uma tarefa mais fácil de se executar.
Para instalar o plugin ElasticSearch, você pode usar o composer
. A partir do
diretório raiz de sua aplicação (onde o arquivo composer.json está localizado)
execute o seguinte:
php composer.phar require cakephp/elastic-search "^2.0"
Você precisará adicionar a seguinte linha ao arquivo config/bootstrap.php da sua aplicação:
Plugin::load('Cake/ElasticSearch', ['bootstrap' => true]);
Adicionalmente, você precisará configurar a conexão como um datasource chamado “elastic” no seu arquivo config/app.php. Um exemplo de configuração ficaria assim:
// No config/app.php
'Datasources' => [
// outros datasources
'elastic' => [
'className' => 'Cake\ElasticSearch\Datasource\Connection',
'driver' => 'Cake\ElasticSearch\Datasource\Connection',
'host' => '127.0.0.1',
'port' => 9200,
'index' => 'my_apps_index',
],
]
O plugin ElasticSearch torna fácil interagir com um índice do elasticsearch e
disponibiliza uma interface similar ao ORM. Para começar, você deve
criar um objeto Index
. Objetos Index
são a classe similar a um
«repositório» ou «tabela» no elasticsearch:
// No src/Model/Index/ArticlesIndex.php
namespace App\Model\Index;
use Cake\ElasticSearch\Index;
class ArticlesIndex extends Index
{
}
Você pode então usar a sua classe type nos seus controllers:
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
// Carrega o Index usando o provedor 'Elastic'
$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'));
}
Nós também precisamos criar um template básico para exibir nossos artigos indexados:
// No src/Template/Articles/add.ctp
<?= $this->Form->create($article) ?>
<?= $this->Form->input('title') ?>
<?= $this->Form->input('body') ?>
<?= $this->Form->button('Save') ?>
<?= $this->Form->end() ?>
Agora você deve conseguir submeter o formulário e ter um novo documento adicionado ao elasticsearch.
Como no ORM, o ODM do ElasticSearch usa classes semelhantes a Entidades. A classe base a partir
da qual você deve indicar herança é a Cake\ElasticSearch\Document
. Classes
de documento podem ser encontradas sob o namespace Model\Document
da sua
aplicação ou plugin:
namespace App\Model\Document;
class Article extends Document
{
}
Fora da lógica do construtor que faz Documents trabalharem com dados do
elasticsearch, a interface e as funcionalidades disponibilizadas pelo objeto
Document
são as mesmas do Entidades.
Depois que você indexar alguns documentos, é hora de buscar por eles. O plugin ElasticSearch disponibiliza um query builder que permite a você construir queries de busca:
$query = $this->Articles->find()
->where([
'title' => 'special',
'or' => [
'tags in' => ['cake', 'php'],
'tags not in' => ['c#', 'java']
]
]);
foreach ($query as $article) {
echo $article->title;
}
Você pode usar o QueryBuilder
para adicionar condições de filtragem:
$query->where(function ($builder) {
return $builder->and(
$builder->gt('views', 99),
$builder->term('author.name', 'sally')
);
});
Se você quiser fazer uma busca textual (fulltext), incluíndo ranqueamento, você
precisa chamar mustWhere
ou shouldWhere
ao invés de where
:
$query->mustWhere(function ($builder) {
return $builder->match('article.body', 'post');
});
Desta forma, você pode, por exemplo, ordenar os resultados em cima do campo
_score
.
A lista completa de métodos com exemplos práticos pode ser encontradda no código fonte do QueryBuilder.
Como no ORM, o plugin ElasticSearch permite validar dados ao ordenar documentos. Validar dados da requisição e aplicar regras da aplicação funcionam da mesma forma como no ORM relacional. Veja a seção validating request data e a seção Application Rules para mais informações.
Quando você estiver pronto para indexar dados no elasticsearch, primeiramente
será necessário converter seus dados em um Document
para que possam ser
indexados:
$article = $this->Articles->newEntity($data);
if ($this->Articles->save($article)) {
// Document indexado
}
Ao ordenar um documento, você pode especificar quais incorporações você deseja
processar usando a chave associated
:
$article = $this->Articles->newEntity($data, ['associated' => ['Comments']]);
Salvar um documento irá disparar os seguintes eventos:
Model.beforeSave
- Disparado antes do documento ser salvo. Você pode
prevenir a operação ao parar este evento.
Model.buildRules
- Disparado quando o verificador de regras é construído
pela primeira vez.
Model.afterSave
- Disparado depois do documento ser salvo.
Nota
Não existem eventos para documentos incorporados devido ao documento pai e todos os seus documentos incorporados serem salvos em uma única operação.
Quando você precisar re-indexar dados, você pode acrescentar informações a entities existentes e salvá-las novamente:
$query = $this->Articles->find()->where(['user.name' => 'jill']);
foreach ($query as $doc) {
$doc->set($newProperties);
$this->Articles->save($doc);
}
Depois de requisitar um documento, você pode deletá-lo:
$doc = $this->Articles->get($id);
$this->Articles->delete($doc);
Você também pode deletar documentos que correspondem condições específicas:
$this->Articles->deleteAll(['user.name' => 'bob']);
Ao definir documentos incorporados, você pode anexar classes de entidade a
caminhos de propriedade específicos em seus documentos. Isso permite a você
sobrescrever o comportamento padrão dos documentos relacionados a um
parente. Por exemplo, você pode querer ter os comentários incorporados a um
artigo para ter acesso a métodos específicos da aplicação. Você pode usar os
métodos embedOne
e embedMany
para definir documentos incorporados:
// No 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'
]);
}
}
O código acima deve criar dois documentos incorporados ao documento Article
.
O User
incorporado irá converter a propriedade user
em instâncias de
App\Model\Document\User
. Para que os comentários incorporados usem um nome
de classe que não correspondem ao nome da propriedade, podemos usar a opção
entityClass
para configurar um nome de classe opcional.
Uma vez que configuramos nossos documentos incorporados, os resultados do
find()
e get()
retornarão objetos com as classes de documentos
incorporados corretas:
$article = $this->Articles->get($id);
// Instância de App\Model\Document\User
$article->user;
// Array das instâncias App\Model\Document\Comment
$article->comments;
Como no ORM, o plugin ElasticSearch disponibiliza um factory/registry para
receber instâncias Index
:
use Cake\ElasticSearch\IndexRegistry;
$articles = IndexRegistry::get('Articles');
Durante casos de testes você pode querer descarregar o registry. Fazê-lo é frequentemente útil quando
During test cases you may want to flush the registry. Doing so is often useful when you are using mock objects, or modifying a type’s dependencies:
IndexRegistry::flush();
O plugin ElasticSearch disponibiliza integração com suites de testes sem remendos. Tais como nas suites de banco de dados, você criar suites de testes para o elasticsearch. Podemos definir uma suite de teste para nosso articles type com o seguinte código:
namespace App\Test\Fixture;
use Cake\ElasticSearch\TestSuite\TestFixture;
/**
* Articles fixture
*/
class ArticlesFixture extends TestFixture
{
/**
* A table/type para essa fixture.
*
* @var string
*/
public $table = 'articles';
/**
* O mapeamento de dados.
*
* @var array
*/
public $schema = [
'id' => ['type' => 'integer'],
'user' => [
'type' => 'nested',
'properties' => [
'username' => ['type' => 'string'],
]
]
'title' => ['type' => 'string'],
'body' => ['type' => 'string'],
];
public $records = [
[
'user' => [
'username' => 'birl'
],
'title' => 'Primeiro post',
'body' => 'Conteúdo'
]
];
}
A propriedade Schema
usa o formato de mapeamento para elasticsearch nativo.
Você pode seguramente omitir o type name e a chave propertires
. Uma vez
que suas fixtures estejam criadas, você pode usá-las nos seus casos de testes
ao incluí-las nas propriedades dos seus fixtures
de testes:
public $fixtures = ['app.articles'];