Skip to content

Instantly share code, notes, and snippets.

@andrewmclagan
Created February 2, 2017 21:43
Show Gist options
  • Select an option

  • Save andrewmclagan/7525400afe2e6ecd74c432e7ca40fd41 to your computer and use it in GitHub Desktop.

Select an option

Save andrewmclagan/7525400afe2e6ecd74c432e7ca40fd41 to your computer and use it in GitHub Desktop.
Elasticsearch indexer
<?php
namespace App\Services;
use Illuminate\Support\Collection;
use Illuminate\Database\Eloquent\Model;
use Elasticsearch\Client;
use App\Models;
/**
* Indexes documents in elasticsearch
*
* @author Andrew McLagan <andrew@ethicaljobs.com.au>
*/
class ElasticsearchIndexer
{
/**
* Elastic search client
*
* @param \Elasticsearch\Client
*/
private $elasticsearch;
/**
* Elastic search index
*
* @param String
*/
private $index;
/**
* Size of collection request chunks
*
* @param Integer
*/
private $chunkSize;
/**
* Indexable eloquent models
*
* @param Array
*/
public $indexableModels = [
Models\Job::class,
];
/**
* Constructor
*
* @param \Elasticsearch\Client $elasticsearch
* @return void
*/
public function __construct(Client $elasticsearch, $chunkSize = 125)
{
$this->elasticsearch = $elasticsearch;
$this->chunkSize = $chunkSize;
$this->index = config('elasticsearch.index');
}
/**
* Indexes a single model instance
*
* @param \App\Models\Model $entity
* @return Array
*/
public function indexEntity(Model $entity)
{
$params = $this->getParamsByEntity($entity);
return $this->elasticsearch->index($params);
}
/**
* Removes a document from the index
*
* @param \App\Models\Model $entity
* @return Array
*/
public function deleteEntity(Model $entity)
{
$params = $this->getParamsByEntity($entity, true);
return $this->elasticsearch->delete($params);
}
/**
* Indexes a collection of entities
*
* @param \Illuminate\Support\Collection $collection
* @return Array
*/
public function indexCollection(Collection $collection)
{
return $this->collectionOperation($collection, false);
}
/**
* Removes a collection of entities from the index
*
* @param \Illuminate\Support\Collection $collection
* @return Array
*/
public function deleteCollection(Collection $collection)
{
return $this->collectionOperation($collection, true);
}
/**
* Indexes all model entities by eloquent class
*
* @param String $class
* @return Void
*/
public function indexAllEntities($class)
{
if ($collection = $this->getModelEntities($class)) {
$this->indexCollection($collection);
}
}
/**
* Remove all model entities by eloquent class
*
* @param String $class
* @return Void
*/
public function deleteAllEntities($class)
{
if ($collection = $this->getModelEntities($class)) {
$this->deleteCollection($collection);
}
}
/**
* Indexes entire database
*
* @return Void
*/
public function indexAll()
{
foreach ($this->indexableModels as $class) {
$this->indexAllEntities($class);
}
}
/**
* Removes all documents from elasticsearch
*
* @return Void
*/
public function deleteAll()
{
return $this->elasticsearch->indices()->delete([
'index' => $this->index,
]);
}
/**
* Runs an operation on a collection
*
* @param \Illuminate\Support\Collection $collection
* @param Boolean $delete
* @return Array
*/
protected function collectionOperation(Collection $collection, $delete = false)
{
$chunks = $collection->chunk($this->chunkSize);
$results = [];
$counter = 1;
$totalChunks = $chunks->count();
dump("Chunks discovered: {$chunks->count()} with a size of: {$this->chunkSize}");
foreach ($chunks as $chunk) {
dump("Executing chunk: {$counter}/{$totalChunks}");
$params = $this->getParamsByCollection($chunk, $delete);
$result = $this->elasticsearch->bulk($params);
$results = array_merge($results, $result); // this is faulty we need a proper merge routine.
$counter++;
}
return $results;
}
/**
* Gets all entities of an indexable model
*
* @return Void
*/
protected function getModelEntities($class)
{
dump("Fetching indexable entities: {$class}");
return (new $class)
->newQuery()
->withoutGlobalScopes()
->get(['*']);
}
/**
* Creates parameters from a single entity
*
* @param \App\Models\Model $entity
* @param Bool $delete
* @return Array
*/
protected function getParamsByEntity($entity, $delete = false)
{
$params = [
'index' => $this->index,
'id' => $entity->id,
'type' => $entity->getTable(),
'body' => $entity->toArray(),
];
return $delete ? array_except($params, 'body') : $params;
}
/**
* Creates parameters from a collection of entities
*
* @param \Illuminate\Support\Collection $entity
* @param Bool $delete
* @return Array
*/
protected function getParamsByCollection(Collection $collection, $delete = false)
{
$actionKey = $delete ? 'delete' : 'index';
$params = [];
foreach ($collection as $entity) {
$params['body'][] = [
$actionKey => [
'_id' => $entity->id,
'_type' => $entity->getTable(),
'_index' => $this->index,
],
];
if (! $delete) {
$params['body'][] = $entity->toArray();
}
}
return $params;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment