Bu örneğimizde elasticsearch aggregation özelliğini kullanacağız. Örneğimiz öğrencileri isimlerine göre name alanına bakarak arayacak. Arama sonucundaki "aggregation" bölümü, aynı tablodaki awards alanını kullanacak.


Veritabanı


ID      NAME                  AWARDS
1 John Travolta ["HND","BSc","MSc"]
2 John Bon Jovi ["HND","MBA"]
3 John Legend ["MBA"]
4 John Cena []
5 Robert De Niro ["MBA"]
6 Roberto Di Baggio []
7 Name John ["MSc"]
8 Name John Surname ["MSc"]

Elastica bundle


Kurulum


Öncelikle composer ile friendsofsymfony/elastica-bundle paketini kurun ve AppKernel.php dosyasında aktifleştirin.


Config.yml


Sadece name alanını full-text arama için ayarlıyoruz çünkü uygulmamız sadece o alanı kullanacak.


fos_elastica:
clients:
default: { host: 127.0.0.1, port: 9200 }
indexes:
student_index:
client: default
index_name: student_%kernel.environment%
types:
student:
mappings:
id:
type: integer
index: not_analyzed
name:
type: string
analyzer: english
awards:
type: string
index: not_analyzed
persistence:
driver: orm
model: AppBundle\Entity\Student
finder: ~
provider: ~
listener: ~

Elasticsearch index


Mevcut durum


Aşağıda da gördüğümüz gibi index henüz mevcut değil.


$ curl 127.0.0.1:9200/_cat/indices?v
health status index pri rep docs.count docs.deleted store.size pri.store.size

Doldurma işlemi


$ bin/console fos:elastica:populate --env=test
Resetting student_index
8/8 [============================] 100%
Populating student_index/student
Refreshing student_index
Refreshing student_index

Yeni durum


Aşağıda da gördüğümüz gibi index yaratılmış durumda.


$ curl 127.0.0.1:9200/_cat/indices?v
health status index pri rep docs.count docs.deleted store.size pri.store.size
yellow open student_test 5 1 8 0 16.2kb 16.2kb

İçerik


$ curl -XGET 127.0.0.1:9200/student_test/_search?pretty=1
{
...
"hits" : {
"total" : 8,
"hits" : [ {
...
"_source":{"id":4,"name":"John Cena","awards":[]}
}, {
...
"_source":{"id":5,"name":"Robert De Niro","awards":["MBA"]}
}, {
...
"_source":{"id":1,"name":"John Travolta","awards":["HND","BSc","MSc"]}
}, {
...
"_source":{"id":6,"name":"Roberto Di Baggio","awards":[]}
}, {
...
"_source":{"id":2,"name":"John Bon Jovi","awards":["HND","MBA"]}
}, {
...
"_source":{"id":7,"name":"Name John","awards":["MSc"]}
}, {
...
"_source":{"id":3,"name":"John Legend","awards":["MBA"]}
}, {
...
"_source":{"id":8,"name":"Name John Surname","awards":["MSc"]}
} ]
}
}

StudentController


namespace AppBundle\Controller;

use AppBundle\Service\StudentService;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;

/**
* @Route("/students", service="app.controller.student")
*/
class StudentController
{
private $studentService;

public function __construct(
StudentService $studentService
) {
$this->studentService = $studentService;
}

/**
* @param Request $request
*
* @Method({"GET"})
* @Route("/search")
* @Template
*
* @return array
*/
public function searchAction(Request $request)
{
$name = $request->query->get('name');

return ['result' => $this->studentService->search($name)];
}
}

services:
app.controller.student:
class: AppBundle\Controller\StudentController
arguments:
- "@app.service.student"

StudentService


namespace AppBundle\Service;

use AppBundle\Factory\ModelFactory;
use Elastica\Query;
use Elastica\Type;

class StudentService
{
private $modelFactory;
private $studentType;

public function __construct(
ModelFactory $modelFactory,
Type $studentType
) {
$this->modelFactory = $modelFactory;
$this->studentType = $studentType;
}

public function search($name)
{
$query['query']['match']['name']['query'] = $name;
$query['aggs']['awards']['terms']['field'] = 'awards';

$result = $this->studentType->search(new Query($query));

return $this->modelFactory->createStudentSearchResult($result);
}
}

services:
app.service.student:
class: AppBundle\Service\StudentService
arguments:
- "@app.factory.model"
- "@fos_elastica.index.student_index.student"

ModelFactory


namespace AppBundle\Factory;

use AppBundle\Model\Search\Result as ResultModel;
use Elastica\ResultSet;

class ModelFactory
{
public function createStudentSearchResult(ResultSet $resultSet)
{
$resultModel = new ResultModel();

if ($resultSet->getTotalHits() < 1) {
return $resultModel;
}

$resultModel->total = $resultSet->getTotalHits();
$resultModel->aggregations = array_column($resultSet->getAggregations()['awards']['buckets'], 'doc_count', 'key');

/** @var \Elastica\Result $item */
foreach ($resultSet->getResults() as $item) {
$data = $item->getData();

$studentModel = new StudentModel();
$studentModel->id = $data['id'];
$studentModel->name = $data['name'];
$studentModel->awards = $data['awards'];

$resultModel->students[] = $studentModel;
}

return $resultModel;
}
}

services:
app.factory.model:
class: AppBundle\Factory\ModelFactory

Result


namespace AppBundle\Model\Search;

class Result
{
/**
* @var int
*/
public $total;

/**
* @var array
*/
public $aggregations;

/**
* @var Student[]
*/
public $students;
}

Student


namespace AppBundle\Model\Search;

class Student
{
/**
* @var int
*/
public $id;

/**
* @var string
*/
public $name;

/**
* @var array
*/
public $awards;
}

Search.html.twig


{% extends '::base.html.twig' %}

{% block body %}
{{ dump(result) }}
{% endblock %}

Test


Eğer http://student.dev/app_test.php/students/search?name=john adresine john ismindeki öğrencileri aramak için giderseniz, aşağıdakine benzer bir sonuç alırsınız. Eğer aggregations bölümündeki veriyi, asıl sonuç ile karşılaştırırsanız, sonuçların uyduğunu göreceksiniz.


AppBundle\Model\Search\Result Object
(
[total] => 6
[aggregations] => Array
(
[MSc] => 3
[HND] => 2
[MBA] => 2
[BSc] => 1
)
[students] => Array
(
[0] => AppBundle\Model\Student Object
(
[id] => 1
[name] => John Travolta
[awards] => Array
(
[0] => HND
[1] => BSc
[2] => MSc
)
)
[1] => AppBundle\Model\Student Object
(
[id] => 7
[name] => Name John
[awards] => Array
(
[0] => MSc
)
)
[2] => AppBundle\Model\Student Object
(
[id] => 3
[name] => John Legend
[awards] => Array
(
[0] => MBA
)
)
[3] => AppBundle\Model\Student Object
(
[id] => 2
[name] => John Bon Jovi
[awards] => Array
(
[0] => HND
[1] => MBA
)
)
[4] => AppBundle\Model\Student Object
(
[id] => 8
[name] => Name John Surname
[awards] => Array
(
[0] => MSc
)
)
[5] => AppBundle\Model\Student Object
(
[id] => 4
[name] => John Cena
[awards] => Array
(
)
)
)
)