Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update for SiteTree Objects #6

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 46 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,56 @@ Usage
-----

The first step is to configure the Elastic Search service. To do this, the configuration system
is used. The simplest default configuration is:
is used. The simplest default configuration (i.e. for `mysite/_config/injector.yml`) is:

Injector:
SilverStripe\Elastica\ElasticaService:
constructor:
- %$Elastica\Client
- index-name-to-use

You cna then use the `SilverStripe\Elastica\Searchable` extension to add searching functionality
to your data objects. Elastic search can then be interacted with using the
`SilverStripe\Elastica\ElasticService` class.
You can then use the `SilverStripe\Elastica\Searchable` extension to add search functionality
to your data objects.

You could, for example add the following code to `mysite/_config/injector.yml`:

SiteTree:
extensions:
- 'SilverStripe\Elastica\Searchable'

Elasticsearch can then be interacted with by using the `SilverStripe\Elastica\ElasticService` class.

To add special fields to the index, just update $searchable_fields of an object:

class SomePage extends Page
{
private static $db = array(
"SomeField1" => "Varchar(255)",
"SomeField2" => "Varchar(255)"
);
private static $searchable_fields = array(
"SomeField1",
"SomeField2"
);
}

After every change to your data model you should execute the `SilverStripe-Elastica-ReindexTask`:

php framework/cli-script.php dev/tasks/SilverStripe-Elastica-ReindexTask

Sometimes you might want to change documents or mappings (eg. for special boosting settings) before they are sent to elasticsearch.
For that purpose just add some methods to your Classes:

class SomePage extends Page
{
public static function updateElasticsearchMapping(\Elastica\Type\Mapping $mapping)
{
return $mapping;
}

public function updateElasticsearchDocument(\Elastica\Document $document)
{
return $document;
}
}

128 changes: 118 additions & 10 deletions src/SilverStripe/Elastica/ElasticaService.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@ class ElasticaService {
*/
protected $buffered = false;

/**
* @var \Elastica\Client Elastica Client object
*/
private $client;

/**
* @var string index name
*/
private $index;

/**
Expand Down Expand Up @@ -56,25 +63,63 @@ public function search($query) {
return new ResultList($this->getIndex(), Query::create($query));
}

/**
* Ensure that the index is present
*/
protected function ensureIndex()
{
$index = $this->getIndex();
if (!$index->exists())
{
$index->create();
}
}

/**
* Ensure that there is a mapping present
*
* @param \Elastica\Type Type object
* @param \DataObject Data record
* @return \Elastica\Mapping Mapping object
*/
protected function ensureMapping(\Elastica\Type $type, \DataObject $record)
{
try
{
$mapping = $type->getMapping();
}
catch(\Elastica\Exception\ResponseException $e)
{
$this->ensureIndex();
$mapping = $record->getElasticaMapping();
$type->setMapping($mapping);
}
return $mapping;
}

/**
* Either creates or updates a record in the index.
*
* @param Searchable $record
*/
public function index($record) {
$document = $record->getElasticaDocument();
$type = $record->getElasticaType();
$typeName = $record->getElasticaType();

if ($this->buffered) {
if (array_key_exists($type, $this->buffer)) {
$this->buffer[$type][] = $document;
if (array_key_exists($typeName, $this->buffer)) {
$this->buffer[$typeName][] = $document;
} else {
$this->buffer[$type] = array($document);
$this->buffer[$typeName] = array($document);
}
} else {
$index = $this->getIndex();

$index->getType($type)->addDocument($document);
$type = $index->getType($typeName);

$this->ensureMapping($type, $record);

$type->addDocument($document);
$index->refresh();
}
}
Expand Down Expand Up @@ -120,9 +165,11 @@ public function remove($record) {
public function define() {
$index = $this->getIndex();

if (!$index->exists()) {
$index->create();
# Recreate the index
if ($index->exists()) {
$index->delete();
}
$index->create();

foreach ($this->getIndexedClasses() as $class) {
/** @var $sng Searchable */
Expand All @@ -134,6 +181,69 @@ public function define() {
}
}

/**
* Refresh a list of records in the index
*
* @param \DataList $records
*/
protected function refreshRecords($records)
{
foreach ($records as $record) {
if ($record->showRecordInSearch()) {
$this->index($record);
}
}

}

/**
* Get a List of all records by class. Get the "Live data" If the class has the "Versioned" extension
*
* @param string $class Class Name
* @return \DataObject[] $records
*/
protected function recordsByClassConsiderVersioned($class)
{
if ($class::has_extension("Versioned")) {
$records = \Versioned::get_by_stage($class, 'Live');
} else {
$records = $class::get();
}
return $records->toArray();
}

/**
* Refresh the records of a given class within the search index
*
* @param string $class Class Name
*/
protected function refreshClass($class)
{
$records = $this->recordsByClassConsiderVersioned($class);

if ($class::has_extension("Translatable")) {

$original_locale = \Translatable::get_current_locale();
$existing_languages = \Translatable::get_existing_content_languages($class);

if (isset($existing_languages[$original_locale])) {
unset($existing_languages[$original_locale]);
}

foreach($existing_languages as $locale => $langName) {
\Translatable::set_current_locale($locale);
$langRecords = $this->recordsByClassConsiderVersioned($class);
foreach ($langRecords as $record)
{
$records[] = $record;
}
}
\Translatable::set_current_locale($original_locale);
}

$this->refreshRecords($records);
}

/**
* Re-indexes each record in the index.
*/
Expand All @@ -142,9 +252,7 @@ public function refresh() {
$this->startBulkIndex();

foreach ($this->getIndexedClasses() as $class) {
foreach ($class::get() as $record) {
$this->index($record);
}
$this->refreshClass($class);
}

$this->endBulkIndex();
Expand Down
15 changes: 12 additions & 3 deletions src/SilverStripe/Elastica/ResultList.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@
*/
class ResultList extends \ViewableData implements \SS_Limitable, \SS_List {

private $index;
/**
* @var \Elastica\Index
*/
private $index;

/**
* @var \Elastica\Query
*/
private $query;

public function __construct(Index $index, Query $query) {
Expand Down Expand Up @@ -50,7 +57,7 @@ public function getIterator() {
public function limit($limit, $offset = 0) {
$list = clone $this;

$list->getQuery()->setLimit($limit);
$list->getQuery()->setSize($limit);
$list->getQuery()->setFrom($offset);

return $list;
Expand Down Expand Up @@ -90,7 +97,9 @@ public function toArray() {
foreach ($found as $item) {
// Safeguards against indexed items which might no longer be in the DB
if(array_key_exists($item->getId(), $retrieved[$item->getType()])) {
$result[] = $retrieved[$item->getType()][$item->getId()];
$data_object = $retrieved[$item->getType()][$item->getId()];
$data_object->setElasticaResult($item);
$result[] = $data_object;
}
}

Expand Down
Loading