How to search with elasticsearch using Yii2

Elasticsearch is a type of Data ware house, where you have documents with many different attributes and non-predictable schemas. It will stored all the records in his document based object and you will be able to search them easily and quickly.It doesn't have tables and schema is not required in elasticsearch . It will stores data documents that consist of JSON strings inside an index.



If you need to setup elasticsearch in your machine please read this post How to install and use elastic search server in ubuntu .Now in this lession i will describe you how we used elasticsearch in yii2 .

The main features of elasticsearch are:
  • Distributed (data can be distributed to thousands of nodes).
  • Very powerful searches.
  • Easy to Scale ( can scale to thousands of nodes easily)
  • Real-time ( the data is available almost immediately after inserts)

When you save a document in Elasticsearch, you save it in an index. An index is like a database in relational database. An index is saved across multiple shards and shards are then stored in one or more servers which are called nodes, multiple nodes form a cluster.

{
    "id": 1,
    "name": "John",
    "author_name": "John"
    "publisher_name": "Admin",
    "created_at": "2016-09-03",
    "updated_at": "2016-09-03",
    "status": "1"
}

Installing elasticsearch using composer in Yii2:

Add following line in your composer.json file.


"yiisoft/yii2-elasticsearch": "~2.0.0"

After adding the line, run the following command in the terminal.

composer update

After succesfully installing the elasticsearch configure the host address of elasticsearch.
Application Folder -> config -> main.php

'elasticsearch' => [
    'class' => 'yii\elasticsearch\Connection',
    'nodes' => [
    ['http_address' => '127.0.0.1:9200'],
    //configure more hosts if you have a cluster
    ],
],

Using Elasticsearch in Yii2: You need to simple extend your model class with \yii\elasticsearch\ActiveRecord.The activerecord we are using for accessing elasticsearch database.Now create a several method for indexing and mapping of data.

<?php

namespace frontend\models;

use Yii;

/**
 * @author     SJ <imsonujangra@gmail.com>
 * @package    Users elastic search 
 * @created    03-Sept-2016
 * @version    1.0
 */
Class Users extends \yii\elasticsearch\ActiveRecord
{

    // Other class attributes and methods go here
    // ...
    public static function index()
    {
        return "sample";//index name
    }

    public static function type()
    {
        return "sample";//index type
    }

    public function attributes()
    {
        return [
            'name',
            'author_name',
            'publisher_name',
            'created_at',
            'updated_at',
            'status'
        ];
    }

    /**
     * @return array This model's mapping
     */
    public static function mapping()
    {
        return [
            static::type() => [
                'properties' => [
                    'name' => ['type' => 'string',"index" => "analyzed","store" => "yes"],
                    'author_name' => ['type' => 'string'],
                    'publisher_name' => ['type' => 'string'],
                    'created_at' => ['type' => 'date'],
                    'updated_at' => ['type' => 'date'],
                    'status' => ['type' => 'long'],
                ]
            ],
        ];
    }

    public static function setUpMapping()
    {
        $db = static::getDb();

        //in case you are not using elasticsearch ActiveRecord so current class extends database ActiveRecord yii/db/activeRecord
        // $db = yii\elasticsearch\ActiveRecord::getDb();

        $command = $db->createCommand();

        /*
         * you can delete the current mapping for fresh mapping but this not recommended and can be dangrous.
         */

        // $command->deleteMapping(static::index(), static::type());

        $command->setMapping(static::index(), static::type(), [
            static::type() => [
                //"_id" => ["path" => "id", "store" => "yes"],
                "properties" => [
                    'name' => ["type" => "string","index" => "analyzed","store" => "yes"],
                    'author_name' => ["type" => "string"],
                    'publisher_name' => ["type" => "string"],
                    'created_at' => ["type" => "date"],
                    'updated_at' => ["type" => "date"],
                    'status' => ["type" => "long"],
                ],
            ],
        ]);
    //echo "<pre>";print_r($command);die;
    }

    /**
     * Set (update) mappings for this model
     */
    public static function updateMapping()
    {
        $db = static::getDb();
        $command = $db->createCommand();
        $command->setMapping(static::index(), static::type(), static::mapping());
    }

    /**
     * Create this model's index
     */
    public static function createIndex()
    {
        $db = static::getDb();
        $command = $db->createCommand();


        $command->createIndex(static::index(), [
            //'settings' => [ /* ... */],
            'mappings' => static::mapping(),
            //'warmers' => [ /* ... */ ],
            //'aliases' => [ /* ... */ ],
            //'creation_date' => '...'
        ]);
    }

    /**
     * Delete this model's index
     */
    public static function deleteIndex()
    {
        $db = static::getDb();
        $command = $db->createCommand();
        $command->deleteIndex(static::index(), static::type());
    }
    
}

Create a controller and use the model class for users operation .Add use frontend\models\Users in your controller namespace and create a object on model class to use its static functions for index creation and update mapping etc.

Create an index :

$userObj = new Users();
$userObj::createIndex();

This command create an index mapping for the name given in your model class Users.

After successfully creating the index in your elasticsearch . you can check the index is created or not using to hit the address in your browser.

http://localhost:9200/sample/_search?pretty

Now the sample index are empty . Its time to add some document in index of elasticsearch.

$userObj = new Users();
$userObj->name   = "Dino";
$userObj->author_name = "Dino";
$userObj->publisher_name = "Admin";
$userObj->created_at = date('Y-m-d');
$userObj->updated_at = date('Y-m-d');
$userObj->status = 1;
$userObj->save();

please check the mapping function for model class in which data type of given fields are mentioned and also which field we need for index stored etc.This command will add a new data in elasticsearch. Add some more data to elasticsearch then check the records using

ttp://localhost:9200/sample/_search?pretty

You can also try to use hq and head plugin to see the document of index in graphical interface.I'm using head plugin and insert some test records like..

elasticsearch head plugin


Then how to search a record in elasticsearch using yii2. In mapping we add the stored to yes . it means we can perform the operations on it.

$userObj = new Users();
$result = $userObj::find()->query(["match" => ["name" => "Peter"]])->all();
echo "<pre>";print_r($result);die;

It will display all records match will the name peter in your index of elasticsearch.You can run the query like this also.

use yii\elasticsearch\Query;
 
$query = new Query();
$query->source('*');
$query->from(Users::index(), Users::type())->limit(10);
 
//execute the query
$command = $query->createCommand();
$rows = $command->search(); 

For the aggregation in query your can use like:

$query->addAggregation("status", "terms", array("field"=>"status" , "order" => ['_term' => "asc"]));
$query->addAggregation("author_name", "terms", array("field"=>"author_name",'size' => 25));

For elasticsearch Query and ActiveRecord you can follow the yii2 document here. If you find this post is intresting please like comment and share.



2 comments:

Download the eBook of react js for beginners

ReactJS basically is an open-source JavaScript library which is used for building user interfaces specifically for single page applications...

Popular