Eğer veritabanı yapınızda ilişkilendirilmiş tablolar varsa ve de siz bunları elasticsearch ile sorgulamak istiyorsanız, aşağıdaki örneği kullanabilirsiniz. Bu örnek FOSElasticaBundle paketini kullanıyor.

Join sorgulamalarında performans arttırmak isterseniz, Handling Relationships sayfasını dikkatlice okumanız gerekir. Özellikle "Application-side Joins", "Denormalizing Your Data" ve "Nested Objects" alanlarına dikkat edin.


Kurulum


Öncelikle composer ile friendsofsymfony/elastica-bundle. Bu yazıyı yazarken friendsofsymfony/elastica-bundle paketi sadece elasticsearch 1.7.4 ve alt versiyonlarını destekliyordu.


Config.yml


Bu ayarlar One to Many (Post - Comment) join içindir.


fos_elastica:
clients:
default: { host: 127.0.0.1, port: 9203 }
indexes:
post_index:
client: default
index_name: post_%kernel.environment%
types:
post:
mappings:
id:
type: integer
index: not_analyzed
title:
type: string
analyzer: english
is_published:
type: boolean
index: not_analyzed
comment:
type: object
properties:
id:
type: integer
index: not_analyzed
message:
type: string
persistence:
driver: orm
model: Application\SearchBundle\Entity\Post
finder: ~
provider: ~
listener: ~

Eğer aynı şeyleri MongoDB ile de yapmak isterseniz, tüm yapmanız gereken "id" alanlarını "string" ve "driver" alanını da "mongodb" yapmaktır.


Post entity


namespace Application\SearchBundle\Entity;

use DateTime;
use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity
* @ORM\Table(name="post")
*/
class Post
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

/**
* @ORM\Column(name="title", type="string", length=100)
*/
private $title;

/**
* @ORM\Column(name="is_published", type="boolean")
*/
private $isPublished;

/**
* @ORM\OneToMany(targetEntity="Comment", mappedBy="post", cascade={"persist", "remove"})
*/
private $comment;
}

Comment entity


namespace Application\SearchBundle\Entity;

use DateTime;
use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity
* @ORM\Table(name="comment")
*/
class Comment
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

/**
* @ORM\Column(name="message", type="text")
*/
private $message;

/**
* @ORM\ManyToOne(targetEntity="Post", inversedBy="comment")
* @ORM\JoinColumn(name="post_id", referencedColumnName="id", onDelete="CASCADE", nullable=false)
*/
private $post;
}

Sorgu 1


Varsayalım ki "post.title" alanında "Eltit" ve "comment.message" alanında "inanzzz" araması yapıyoruz.


Doctrine


return $this
->createQueryBuilder('p')
->select('p, c')
->innerJoin('p.comment', 'c')
->where('p.title LIKE :title')
->andWhere('c.message LIKE :message')
->setParameter('title', '%Eltit%')
->setParameter('message', '%inanzzz%')
->getQuery()
->getResult();

MySQL


SELECT *
FROM post
INNER JOIN comment ON post.id = comment.post_id
WHERE
MATCH(`post`.`title`) AGAINST ('Eltit' IN BOOLEAN MODE) AND
MATCH(`comment`.`message`) AGAINST ('inanzzz' IN BOOLEAN MODE)
#GROUP BY post.id #This would return same amount of records as doctrine and ES

Elasticsearch


curl -XGET "http://127.0.0.1:9203/_search?post_dev" -d'
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "Eltit"
}
},
{
"match": {
"comment.message": "inanzzz"
}
}
]
}
},
"sort": [
{
"_score": {
"order": "desc"
}
}
],
"from": "0",
"size": "10"
}'

Sorgu 2


Varsayalım ki "post.is_published" alanında "true" ve "comment.message" alanında "inanzzz" araması yapıyoruz.


Doctrine


Bunu kendiniz de yapabilirsiniz.


MySQL


Bunu kendiniz de yapabilirsiniz.


Elasticsearch


curl -XGET "http://127.0.0.1:9203/_search?post_dev" -d'
{
"query": {
"filtered": {
"query": {
"match": {
"comment.message": "inanzzz"
}
},
"filter": {
"bool": {
"must_not": {
"term": {
"is_published": "false"
}
}
}
}
}
},
"sort": [
{
"_score": {
"order": "desc"
}
}
],
"from": "0",
"size": "10"
}'