21/05/2016 - ELASTICSEARCH, SYMFONY
Elasticsearch index gets created automatically based on the mapping you define so you don't really need to interfere it. However, you can manually create and manipulate elasticsearch index with a custom model_to_elastica_transformer
service option in configuration instead. In such case, even if you defined fields in mappings
option, they all will be ignored. Example depends on FOSElasticaBundle library.
In the example below, we're going to manipulate actual "price" by increasing it by 1 if the it is less than 4 otherwise decrease it by 1 for only published records and completely ignore indexing unpublished ones.
mysql> SELECT * FROM post LIMIT 10;
+----+---------+-------------+---------------+------+-------+--------------+---------------------+
| id | title | description | author | year | price | is_published | created_at |
+----+---------+-------------+---------------+------+-------+--------------+---------------------+
| 1 | Desc | Cript B | Robert | 2000 | 5.55 | 1 | 2016-05-20 21:14:40 |
| 2 | Desc | Title | Andy Garcia | 2015 | 0.50 | 0 | 2016-05-20 21:15:00 |
| 3 | Eltit | Title 3 | Robert DeNiro | 2005 | 4.00 | 0 | 2016-05-20 21:15:00 |
| 4 | Eltit | Title 3 | Robert | 2015 | 3.99 | 1 | 2016-05-20 21:15:00 |
| 5 | Title 2 | Title 3 | Andy | 2000 | 4.00 | 1 | 2016-05-20 21:15:00 |
| 6 | Eltit B | Desc 1 | Andy | 2010 | 2.50 | 0 | 2016-05-20 21:15:00 |
| 7 | Title 2 | Desc 1 | Pacino | 2000 | 3.99 | 0 | 2016-05-20 21:15:00 |
| 8 | Title 1 | Desc 1 | DeNiro | 2010 | 5.55 | 1 | 2016-05-20 21:15:00 |
| 9 | Eltit A | Cript B | Andy Garcia | 2015 | 5.55 | 1 | 2016-05-20 21:15:00 |
| 10 | Eltit | Desc 2 | Pacino | 2000 | 3.99 | 0 | 2016-05-20 21:15:00 |
+----+---------+-------------+---------------+------+-------+--------------+---------------------+
10 rows in set (0.00 sec)
curl -XPOST "http://127.0.0.1:9200/_search?post_dev" -d'
{
"query": {
"bool": {
"must": [
{
"match_all": []
}
]
}
},
"sort": [
{
"id": {
"order": "id",
"ignore_unmapped": true
}
}
],
"from": "0",
"size": "10"
}'
This example should index all the records in database without a condition and show them to us as is in the query result below.
fos_elastica:
clients:
default: { host: 127.0.0.1, port: 9200 }
indexes:
post_index:
client: default
index_name: post_dev
types:
post:
mappings:
id:
type: integer
title:
type: string
description:
type: string
year:
type: integer
price:
type: double
is_published:
type: boolean
created_at:
type: date
persistence:
driver: orm
model: Application\SearchBundle\Entity\Post
finder: ~
provider: ~
listener: ~
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 15,
"successful": 15,
"failed": 0
},
"hits": {
"total": 1003,
"max_score": null,
"hits": [
{
"_index": "post_dev",
"_type": "post",
"_id": "1",
"_score": null,
"_source": {
"id": 1,
"title": "Desc",
"description": "Cript B",
"year": "2000",
"price": "5.55",
"is_published": true,
"created_at": "2016-05-20T21:14:40+01:00"
},
"sort": [
1
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "2",
"_score": null,
"_source": {
"id": 2,
"title": "Desc",
"description": "Title",
"year": "2015",
"price": "0.50",
"is_published": false,
"created_at": "2016-05-20T21:15:00+01:00"
},
"sort": [
2
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "3",
"_score": null,
"_source": {
"id": 3,
"title": "Eltit",
"description": "Title 3",
"year": "2005",
"price": "4.00",
"is_published": false,
"created_at": "2016-05-20T21:15:00+01:00"
},
"sort": [
3
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "4",
"_score": null,
"_source": {
"id": 4,
"title": "Eltit",
"description": "Title 3",
"year": "2015",
"price": "3.99",
"is_published": true,
"created_at": "2016-05-20T21:15:00+01:00"
},
"sort": [
4
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "5",
"_score": null,
"_source": {
"id": 5,
"title": "Title 2",
"description": "Title 3",
"year": "2000",
"price": "4.00",
"is_published": true,
"created_at": "2016-05-20T21:15:00+01:00"
},
"sort": [
5
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "6",
"_score": null,
"_source": {
"id": 6,
"title": "Eltit B",
"description": "Desc 1",
"year": "2010",
"price": "2.50",
"is_published": false,
"created_at": "2016-05-20T21:15:00+01:00"
},
"sort": [
6
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "7",
"_score": null,
"_source": {
"id": 7,
"title": "Title 2",
"description": "Desc 1",
"year": "2000",
"price": "3.99",
"is_published": false,
"created_at": "2016-05-20T21:15:00+01:00"
},
"sort": [
7
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "8",
"_score": null,
"_source": {
"id": 8,
"title": "Title 1",
"description": "Desc 1",
"year": "2010",
"price": "5.55",
"is_published": true,
"created_at": "2016-05-20T21:15:00+01:00"
},
"sort": [
8
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "9",
"_score": null,
"_source": {
"id": 9,
"title": "Eltit A",
"description": "Cript B",
"year": "2015",
"price": "5.55",
"is_published": true,
"created_at": "2016-05-20T21:15:00+01:00"
},
"sort": [
9
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "10",
"_score": null,
"_source": {
"id": 10,
"title": "Eltit",
"description": "Desc 2",
"year": "2000",
"price": "3.99",
"is_published": false,
"created_at": "2016-05-20T21:15:00+01:00"
},
"sort": [
10
]
}
]
}
}
This example should index only published records in database, set only specific fields as we want, manipulate some values and show them to us in the query result below. Even if you add mappings
options below, they all will be ignored so no point of adding them.
fos_elastica:
clients:
default: { host: 127.0.0.1, port: 9200 }
indexes:
post_index:
client: default
index_name: post_dev
types:
post:
mappings: ~
persistence:
driver: orm
model: Application\SearchBundle\Entity\Post
finder: ~
provider: ~
listener: ~
model_to_elastica_transformer:
service: application_search.service.post_to_elastica_transformer
The line $data['null'] = null;
will not create any record in elasticsearch index.
namespace Application\SearchBundle\Service;
use Application\SearchBundle\Entity\Post;
use DateTime;
use Elastica\Document;
use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface;
class PostToElasticaTransformer implements ModelToElasticaTransformerInterface
{
const PRICE_CAP = 4;
const INCREASE_BY = 1;
const DECREASE_BY = 1;
/**
* @param Post $post
* @param array $fields
*
* @return Document
*/
public function transform($post, array $fields)
{
return new Document($post->getId(), $this->getData($post));
}
private function getData(Post $post)
{
$data = [];
if (!$post->getIsPublished()) {
$data['null'] = null;
} else {
$data['id'] = $post->getId();
$data['title'] = $post->getTitle();
$data['author'] = $post->getAuthor();
$data['year'] = (int)$post->getYear();
$data['price'] = (double)$post->getPrice();
$data['sale_price'] = $this->getSalePrice($post->getPrice());
$data['sale_price_created_at'] = (new DateTime())->format(DateTime::ISO8601);
}
return $data;
}
private function getSalePrice($price)
{
return $price < self::PRICE_CAP ? $price+self::INCREASE_BY : $price-self::DECREASE_BY;
}
}
services:
application_search.util.post_to_elastica_transformer:
class: Application\SearchBundle\Util\PostToElasticaTransformer
As you can see below, unpublished records are ignored and new fields are added to index.
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 15,
"successful": 15,
"failed": 0
},
"hits": {
"total": 1003,
"max_score": null,
"hits": [
{
"_index": "post_dev",
"_type": "post",
"_id": "1",
"_score": null,
"_source": {
"id": 1,
"title": "Desc",
"author": "Robert",
"year": 2000,
"price": 5.55,
"sale_price": 4.55,
"sale_price_created_at": "2016-05-21T21:17:58+0100"
},
"sort": [
1
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "4",
"_score": null,
"_source": {
"id": 4,
"title": "Eltit",
"author": "Robert",
"year": 2015,
"price": 3.99,
"sale_price": 4.99,
"sale_price_created_at": "2016-05-21T21:17:58+0100"
},
"sort": [
4
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "5",
"_score": null,
"_source": {
"id": 5,
"title": "Title 2",
"author": "Andy",
"year": 2000,
"price": 4,
"sale_price": 3,
"sale_price_created_at": "2016-05-21T21:17:58+0100"
},
"sort": [
5
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "8",
"_score": null,
"_source": {
"id": 8,
"title": "Title 1",
"author": "DeNiro",
"year": 2010,
"price": 5.55,
"sale_price": 4.55,
"sale_price_created_at": "2016-05-21T21:17:58+0100"
},
"sort": [
8
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "9",
"_score": null,
"_source": {
"id": 9,
"title": "Eltit A",
"author": "Andy Garcia",
"year": 2015,
"price": 5.55,
"sale_price": 4.55,
"sale_price_created_at": "2016-05-21T21:17:58+0100"
},
"sort": [
9
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "13",
"_score": null,
"_source": {
"id": 13,
"title": "Eltit",
"author": "Pacino",
"year": 2000,
"price": 0.5,
"sale_price": 1.5,
"sale_price_created_at": "2016-05-21T21:17:58+0100"
},
"sort": [
13
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "14",
"_score": null,
"_source": {
"id": 14,
"title": "Title 2",
"author": "Robert DeNiro",
"year": 2000,
"price": 0.5,
"sale_price": 1.5,
"sale_price_created_at": "2016-05-21T21:17:58+0100"
},
"sort": [
14
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "15",
"_score": null,
"_source": {
"id": 15,
"title": "Title 3",
"author": "Al",
"year": 2010,
"price": 2.5,
"sale_price": 3.5,
"sale_price_created_at": "2016-05-21T21:17:58+0100"
},
"sort": [
15
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "17",
"_score": null,
"_source": {
"id": 17,
"title": "Title 2",
"author": "Al",
"year": 2005,
"price": 5.55,
"sale_price": 4.55,
"sale_price_created_at": "2016-05-21T21:17:58+0100"
},
"sort": [
17
]
},
{
"_index": "post_dev",
"_type": "post",
"_id": "18",
"_score": null,
"_source": {
"id": 18,
"title": "Eltit",
"author": "Al",
"year": 2000,
"price": 4,
"sale_price": 3,
"sale_price_created_at": "2016-05-21T21:17:58+0100"
},
"sort": [
18
]
}
]
}
}