Einführung zu Elasticsearch

Elasticsearch ist eine intelligente Volltextsuche. Meine erste Wahl wenn die Volltextsuche von Contao CMS nicht mehr ausreicht. In diesem Beispiel verwende ich mein OCEAN Framework um die Prozesse zu vereinfachen. Eine Contao CMS + Symfony integeration ist genauso möglich. Wenn Sie Ihr Projekt mit Elasticsearch aufrüsten wollen, sprechen Sie mich bitte darauf an. Ich helfe Ihnen gerne weiter.

Elasticsearch installieren

Elasticsearch muss erstmal runtergeladen und installiert werden.

Elasticsearch starten

Um Elasticsearch zu starten muss man in den heruntergeladenen Ordner wechseln und folgenden Befehl ausführen: bin/elasticsearch

Testen ob Elasticsearch funktioniert

Im Browser 192.168.0.102:9200 aufrufen. Es sollte ein json-Object zusehen sein. Wenn Status 200 ist, ist alles okey!

Elasticsearch-PHP installieren mit Composer

Erstelle im Root Ordner eine composer.json Datei ( OCEAN/composer.json ) und füge folgenden code hinzu.

{"require": { "elasticsearch/elasticsearch": "~1.0"}}

Danach composer install ausführen.

Composer autoload einbinden

Dazu im system/initialize.php folgenden code nach dem "classloader" einfügen require 'vendor/autoload.php';

Jetzt kann Elasticsearch aufgerufen werden: $es = new \Elasticsearch\Client();

Wie bereits erwähnt habe ich meinen OCEAN PHP Framework verwendet. Ich habe den UserController verwendet und die bereits implementierten Methoden( create, update, delete ). Zusätzlich habe ich eine neue Methode search() implementiert, aber dazu später mehr. Grundsätzlich ist es egal welches Framework man verwendet.

Dokument Indexieren

Als erstes müssen wir ein Index erstellen. Ein Index kann man mit einer Datenbank vergleichen. Ein Index kann mehrere Types haben. Ein Type ist wie eine Tabelle. Da ich in diesem Beispiel nur User indexiere, verwende ich Plural + Singular Notaion. Mein Index ist "users" und der type ist "user". Im Body können wir festlegen welche Daten wir indexieren möchten. Im Beispiel indexiere ich den "usernamen (:String)", "attributes (:Array)" und "message(:text)".

Index hinzufügen

In der create() Methode füge ich nach dem $user->insert(); folgenden code hinzu:

$es = new \Elasticsearch\Client(); // elasticsearch initialisieren
 
$index = array();
 
$index['index'] = 'users'; //Ein Index ist wie wie eine Datenbank
$index['type']  = 'user'; // Ein Type ist wie eine Tabelle
$index['id']    = $user->id;
 
$index['body']  = array
(
    'username' => $input['username'],
    'attributes' => explode(',', $input['attributes']),
    'message' => $input['message']
);
 
$es->index($index);

Testen ob mein User Indexiert worden ist

Rufe 192.168.0.102:9200/users/_search auf. Man sieht wieder ein json-Object. In diesem sollte der neu erstelle User auftauchen.

Ein Index ändern.

Man kann auch einen Index nachträglich ändern. Für den Beispiel habe ich die update() Methode verwendet. Dort habe ich nach der $user->update(); folgenden code hinzugefügt.

$es = new \Elasticsearch\Client();
$update = array();
$update['index'] = 'users';
$update['type']  = 'user';
$update['id']    = $userID;
$update['body']['doc']  = array
(
    'username' => $input['username'],
    'attributes' => explode(',', $input['attributes']),
    'message' => $input['message']
);
$es->update($update);

Ein Index löschen.

In der delete() Methode habe ich nach dem $user->remove(); folgenden code hinzugefügt.

$es = new \Elasticsearch\Client();
$delete = array();
$delete['index'] = 'users';
$delete['type']  = 'user';
$delete['id']    = $userID;
$es->delete($delete);

Ein Index kann man durch die ID löschen. $delete['id'] = $userID;

Indizes suchen

Für diesen Beispiel habe eine zusätzliche search() Methode im UserController erstellt und mir ein passendes Formular gebastelt.

Search Methode hinzufügen

$GLOBALS['routes'] = array(
    'searchUser' => array(
        'method' => 'get',
        'path' => '/user/search',
        'controller' => 'UserController.search',
    ),
)

Formular

<form method="get" action="/user/search" enctype="multipart/form-data">
    <input type="text" name="q" placeholder="suche"/>
    <input type="submit" class="submit" value="suchen">
</form>

Match Operator

public function search()
{
 
 
    $input = Request::only(array('q'));
    $queryStr = empty($input['q']) ? '' : $input['q'];
 
    $es = new \Elasticsearch\Client();
    $params = array();
    $params['body']['query']['match']['username'] = $queryStr;
    $respone = $es->search($params);
 
    include 'views/page/search.php';
     
 
}

Mit dem match Operator können wir nach Dokumenten suchen. Dabei handelt es sich um eine Volltextsuche. Die $respone variable gibt uns ein Array zurück, mit den gefunden Dokumenten. Wenn $res['hits']['total'] größer 0 ist können wir mit einer schleife die dokumente in $res['hits']['hits'] auslesen.

Match & Filter Operator

public function search()
{
 
    $input = Request::only(array('q'));
    $queryStr = empty($input['q']) ? '' : $input['q'];
 
    $es = new \Elasticsearch\Client();
     
    $params = array();
    $params['index'] = 'users';
    $params['type']  = 'user';
 
    $query = array();
    $query['match']['username'] = $queryStr;
 
    $filter = array();
    $filter['term']['attributes'] = 'weiblich';
         
    $params['body']['query']['filtered'] = array(
        "filter" => $filter,
        "query"  => $query
    );      
 
    $res = $es->search($params);
 
    include 'views/page/search.php';
    var_dump($res);
 
}

Wir können auch Ergebnisse Filtern bevor wir diese "matchen". Wie im Beispiel gezeigt, erst Filtern wir alle weiblichen User und danach suchen wir nach einem bestimmten Namen.

Zurück