diff --git a/Query/QueryAwareTrait.php b/Query/QueryAwareTrait.php
deleted file mode 100644
index 262fdd694193f93565cd366245c043cf1ec07c72..0000000000000000000000000000000000000000
--- a/Query/QueryAwareTrait.php
+++ /dev/null
@@ -1,138 +0,0 @@
-<?php
-
-/*
- * This file is part of the ONGR package.
- *
- * (c) NFQ Technologies UAB <info@nfq.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace ONGR\ElasticsearchBundle\DSL\Query;
-
-use ONGR\ElasticsearchBundle\DSL\Bool\Bool;
-use ONGR\ElasticsearchBundle\DSL\BuilderInterface;
-
-/**
- * Provides query container functionality to any class.
- */
-trait QueryAwareTrait
-{
-    /**
-     * @var BuilderInterface[]
-     */
-    private $queries = [];
-
-    /**
-     * @var \ONGR\ElasticsearchBundle\DSL\Bool\Bool
-     */
-    private $boolQuery;
-
-    /**
-     * @param BuilderInterface $query
-     * @param string           $boolType
-     *
-     * @return $this
-     */
-    public function addQuery(BuilderInterface $query, $boolType = Bool::MUST)
-    {
-        if ($boolType !== Bool::MUST || $this->boolQuery !== null) {
-            $this->getBoolQuery()->addToBool($query, $boolType);
-        } else {
-            $this->queries[$query->getType()] = $query;
-        }
-
-        return $this;
-    }
-
-    /**
-     * Returns Bool query. Creates new instance if there is not initiated.
-     *
-     * @return \ONGR\ElasticsearchBundle\DSL\Bool\Bool
-     */
-    public function getBoolQuery()
-    {
-        if (!$this->boolQuery) {
-            $this->boolQuery = new Bool();
-        }
-
-        return $this->boolQuery;
-    }
-
-    /**
-     * @param array $params Example values:
-     *                      - minimum_should_match => 1
-     *                      - boost => 1.
-     */
-    public function setBoolQueryParameters(array $params)
-    {
-        $this->getBoolQuery()->setParameters($params);
-    }
-
-    /**
-     * Checks if there is added specific query.
-     *
-     * @param string $type Query type.
-     *
-     * @return bool
-     */
-    public function hasQuery($type)
-    {
-        return array_key_exists($type, $this->queries);
-    }
-
-    /**
-     * Removes specific query.
-     *
-     * @param string $key
-     */
-    public function removeQuery($key)
-    {
-        if ($this->hasQuery($key)) {
-            unset($this->queries[$key]);
-        }
-    }
-
-    /**
-     * Completely resets query.
-     */
-    public function destroyQuery()
-    {
-        $this->queries = [];
-        $this->boolQuery = null;
-    }
-
-    /**
-     * Return all queries.
-     *
-     * @return array
-     */
-    public function getQueries()
-    {
-        return $this->queries;
-    }
-
-    /**
-     * Aggregates all queries to array.
-     *
-     * @return array
-     */
-    public function processQueries()
-    {
-        if ($this->boolQuery || count($this->getQueries()) > 1) {
-            $bool = $this->getBoolQuery();
-            foreach ($this->getQueries() as $query) {
-                $bool->addToBool($query);
-            }
-
-            return ['query' => [$bool->getType() => $bool->toArray()]];
-        } elseif (count($this->getQueries()) == 1) {
-            $query = array_values($this->getQueries())[0];
-
-            return ['query' => [$query->getType() => $query->toArray()]];
-        }
-
-        return [];
-    }
-}
diff --git a/Search.php b/Search.php
index 5e9bd482cd94b80d724d0cbe93b0ee23b071c3e6..cd626aed5a27cf95f55f3128f910624129ff5126 100644
--- a/Search.php
+++ b/Search.php
@@ -18,39 +18,24 @@ use ONGR\ElasticsearchBundle\DSL\Highlight\Highlight;
 use ONGR\ElasticsearchBundle\DSL\Query\FilteredQuery;
 use ONGR\ElasticsearchBundle\DSL\Query\Query;
 use ONGR\ElasticsearchBundle\DSL\Query\QueryAwareTrait;
+use ONGR\ElasticsearchBundle\DSL\SearchEndpoint\SearchEndpointFactory;
+use ONGR\ElasticsearchBundle\DSL\SearchEndpoint\SearchEndpointInterface;
 use ONGR\ElasticsearchBundle\DSL\Sort\AbstractSort;
 use ONGR\ElasticsearchBundle\DSL\Sort\Sorts;
 use ONGR\ElasticsearchBundle\DSL\Suggester\AbstractSuggester;
+use ONGR\ElasticsearchBundle\Serializer\Normalizer\CustomReferencedNormalizer;
+use ONGR\ElasticsearchBundle\Serializer\Normalizer\ReferencedNormalizer;
+use ONGR\ElasticsearchBundle\Serializer\OrderedSerializer;
+use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
+use Symfony\Component\Serializer\Serializer;
 
 /**
  * Search object that can be executed by a manager.
  */
 class Search
 {
-    use QueryAwareTrait;
-
     const SCROLL_DURATION = '5m';
 
-    /**
-     * @var array
-     */
-    private $boolQueryParams;
-
-    /**
-     * @var BuilderInterface
-     */
-    private $filters;
-
-    /**
-     * @var BuilderInterface Filters collection.
-     */
-    private $postFilters;
-
-    /**
-     * @var array
-     */
-    private $boolFilterParams;
-
     /**
      * @var int
      */
@@ -61,11 +46,6 @@ class Search
      */
     private $from;
 
-    /**
-     * @var Sorts
-     */
-    private $sorts;
-
     /**
      * @var string|null
      */
@@ -86,16 +66,6 @@ class Search
      */
     private $scriptFields;
 
-    /**
-     * @var NamedBuilderBag
-     */
-    private $suggesters;
-
-    /**
-     * @var Highlight
-     */
-    private $highlight;
-
     /**
      * @var string
      */
@@ -111,11 +81,6 @@ class Search
      */
     private $stats;
 
-    /**
-     * @var NamedBuilderBag
-     */
-    private $aggregations;
-
     /**
      * @var string[]
      */
@@ -127,364 +92,414 @@ class Search
     private $minScore;
 
     /**
-     * @return float
+     * @var Serializer
      */
-    public function getMinScore()
+    private $serializer;
+
+    /**
+     * @var SearchEndpointInterface[]
+     */
+    private $endpoints = [];
+
+    /**
+     * Initializes serializer.
+     */
+    public function __construct()
     {
-        return $this->minScore;
+        $this->serializer = new OrderedSerializer(
+            [
+                new CustomReferencedNormalizer(),
+                new CustomNormalizer(),
+            ]
+        );
     }
 
     /**
-     * Set min score.
+     * Adds query to search.
      *
-     * @param float $minScore
+     * @param BuilderInterface $query
+     * @param string           $boolType
      *
-     * @return $this
+     * @return Search
      */
-    public function setMinScore($minScore)
+    public function addQuery(BuilderInterface $query, $boolType = '')
     {
-        $this->minScore = $minScore;
+        $this
+            ->getEndpoint('query')
+            ->addBuilder($query, ['bool_type' => $boolType]);
 
         return $this;
     }
 
     /**
-     * Set offset.
+     * Sets parameters for bool query.
      *
-     * @param int $from
+     * @param array $params Example values:
+     *                      - minimum_should_match => 1
+     *                      - boost => 1.
      *
-     * @return $this
+     * @return Search
      */
-    public function setFrom($from)
+    public function setBoolQueryParameters(array $params)
     {
-        $this->from = $from;
+        $this
+            ->getEndpoint('query')
+            ->setParameters($params);
 
         return $this;
     }
 
     /**
-     * Set maximum number of results.
+     * Returns contained query.
      *
-     * @param int $size
+     * @return BuilderInterface
+     */
+    public function getQuery()
+    {
+        return $this
+            ->getEndpoint('query')
+            ->getBuilder();
+    }
+
+    /**
+     * Destroys query part.
      *
-     * @return $this
+     * @return Search
      */
-    public function setSize($size)
+    public function destroyQuery()
     {
-        $this->size = $size;
+        $this->destroyEndpoint('query');
 
         return $this;
     }
 
     /**
-     * Add sort.
+     * Adds a filter to search.
      *
-     * @param AbstractSort $sort
+     * @param BuilderInterface $filter   Filter.
+     * @param string           $boolType Possible boolType values:
+     *                                   - must
+     *                                   - must_not
+     *                                   - should.
      *
-     * @return $this
+     * @return Search
      */
-    public function addSort($sort)
+    public function addFilter(BuilderInterface $filter, $boolType = '')
     {
-        if ($this->sorts === null) {
-            $this->sorts = new Sorts();
-        }
+        $this->getEndpoint('query');
 
-        $this->sorts->addSort($sort);
+        $this
+            ->getEndpoint('filter')
+            ->addBuilder($filter, ['bool_type' => $boolType]);
 
         return $this;
     }
 
     /**
-     * Set source.
+     * Returns currently contained filters.
      *
-     * @param array|bool|string $source
-     *
-     * @return $this
+     * @return BuilderInterface
      */
-    public function setSource($source)
+    public function getFilters()
     {
-        $this->source = $source;
-
-        return $this;
+        return $this
+            ->getEndpoint('filter')
+            ->getBuilder();
     }
 
     /**
-     * Set fields.
+     * Sets bool filter parameters.
      *
-     * @param array $fields
+     * @param array $params Possible values:
+     *                      _cache => true
+     *                      false.
      *
-     * @return $this
+     * @return Search
      */
-    public function setFields(array $fields)
+    public function setBoolFilterParameters($params)
     {
-        $this->fields = $fields;
+        $this
+            ->getEndpoint('filter')
+            ->setParameters($params);
 
         return $this;
     }
 
     /**
-     * Set script fields.
-     *
-     * @param array $scriptFields
-     *
-     * @return $this
+     * Destroys filter part.
      */
-    public function setScriptFields($scriptFields)
+    public function destroyFilters()
     {
-        $this->scriptFields = $scriptFields;
-
-        return $this;
+        $this->destroyEndpoint('filter');
     }
 
     /**
+     * Adds a post filter to search.
+     *
      * @param BuilderInterface $postFilter Post filter.
      * @param string           $boolType   Possible boolType values:
      *                                     - must
      *                                     - must_not
      *                                     - should.
      *
-     * @return $this
+     * @return Search
      */
-    public function addPostFilter(BuilderInterface $postFilter, $boolType = 'must')
+    public function addPostFilter(BuilderInterface $postFilter, $boolType = '')
     {
-        if ($this->postFilters === null) {
-            $this->postFilters = new Bool();
-        }
-
-        $this->postFilters->addToBool($postFilter, $boolType);
+        $this
+            ->getEndpoint('post_filter')
+            ->addBuilder($postFilter, ['bool_type' => $boolType]);
 
         return $this;
     }
 
     /**
-     * Sets highlight.
-     *
-     * @param Highlight $highlight
+     * Returns all contained post filters.
      *
-     * @return $this
+     * @return BuilderInterface
      */
-    public function setHighlight($highlight)
+    public function getPostFilters()
     {
-        $this->highlight = $highlight;
-
-        return $this;
+        return $this
+            ->getEndpoint('post_filter')
+            ->getBuilder();
     }
 
     /**
-     * Set search type.
+     * Sets bool post filter parameters.
      *
-     * @param string $searchType
+     * @param array $params Possible values:
+     *                      _cache => true
+     *                      false.
      *
-     * @return $this
+     * @return Search
      */
-    public function setSearchType($searchType)
+    public function setBoolPostFilterParameters($params)
     {
-        $this->searchType = $searchType;
+        $this
+            ->getEndpoint('post_filter')
+            ->setParameters($params);
 
         return $this;
     }
 
     /**
-     * Set explain.
+     * Returns min score value.
      *
-     * @param bool $explain
-     *
-     * @return $this
+     * @return float
      */
-    public function setExplain($explain)
+    public function getMinScore()
     {
-        $this->explain = $explain;
-
-        return $this;
+        return $this->minScore;
     }
 
     /**
-     * Set stats.
+     * Exclude documents which have a _score less than the minimum specified.
      *
-     * @param array $stats
+     * @param float $minScore
      *
-     * @return $this
+     * @return Search
      */
-    public function setStats($stats)
+    public function setMinScore($minScore)
     {
-        $this->stats = $stats;
+        $this->minScore = $minScore;
 
         return $this;
     }
 
     /**
-     * Setter for scroll duration, effectively setting if search is scrolled or not.
+     * Paginate results from.
      *
-     * @param string|null $duration
+     * @param int $from
      *
      * @return Search
      */
-    public function setScroll($duration = self::SCROLL_DURATION)
+    public function setFrom($from)
     {
-        $this->scrollDuration = $duration;
+        $this->from = $from;
 
         return $this;
     }
 
     /**
-     * Setter for preference.
+     * Returns results offset value.
      *
-     * Controls which shard replicas to execute the search request on.
+     * @return int
+     */
+    public function getFrom()
+    {
+        return $this->from;
+    }
+
+    /**
+     * Set maximum number of results.
      *
-     * @param mixed $preferenceParams Possible values:
-     *                                _primary
-     *                                _primary_first
-     *                                _local
-     *                                _only_node:xyz (xyz - node id)
-     *                                _prefer_node:xyz (xyz - node id)
-     *                                _shards:2,3 (2 and 3 specified shards)
-     *                                custom value
-     *                                string[] combination of params.
+     * @param int $size
      *
-     * @return Search $this
+     * @return Search
      */
-    public function setPreference($preferenceParams)
+    public function setSize($size)
     {
-        if (is_string($preferenceParams)) {
-            $this->preference[] = $preferenceParams;
-        }
-
-        if (is_array($preferenceParams) && !empty($preferenceParams)) {
-            $this->preference = $preferenceParams;
-        }
+        $this->size = $size;
 
         return $this;
     }
 
     /**
-     * Returns preference params as string.
+     * Returns maximum number of results query can request.
      *
-     * @return string
+     * @return int
      */
-    protected function getPreference()
+    public function getSize()
     {
-        return implode(';', $this->preference);
+        return $this->size;
     }
 
     /**
-     * Returns scroll duration.
+     * Adds sort to search.
+     *
+     * @param AbstractSort $sort
      *
-     * @return null|string
+     * @return Search
      */
-    public function getScroll()
+    public function addSort(AbstractSort $sort)
     {
-        return $this->scrollDuration;
+        $this
+            ->getEndpoint('sort')
+            ->addBuilder($sort);
+
+        return $this;
     }
 
     /**
-     * @param AbstractAggregation $agg
+     * Returns currectly contained sorts object.
      *
-     * @return $this
+     * @return Sorts
      */
-    public function addAggregation($agg)
+    public function getSorts()
     {
-        if ($this->aggregations === null) {
-            $this->aggregations = new NamedBuilderBag();
-        }
-        $this->aggregations->add($agg);
-
-        return $this;
+        return $this
+            ->getEndpoint('sort')
+            ->getBuilder();
     }
 
     /**
-     * @param BuilderInterface $filter   Filter.
-     * @param string           $boolType Possible boolType values:
-     *                                   - must
-     *                                   - must_not
-     *                                   - should.
+     * Allows to control how the _source field is returned with every hit.
      *
-     * @return $this
+     * @param array|bool|string $source
+     *
+     * @return Search
      */
-    public function addFilter(BuilderInterface $filter, $boolType = 'must')
+    public function setSource($source)
     {
-        if ($this->filters === null) {
-            $this->filters = new Bool();
-        }
-
-        $this->filters->addToBool($filter, $boolType);
+        $this->source = $source;
 
         return $this;
     }
 
     /**
-     * @param array $params Possible values:
-     *                      _cache => true
-     *                      false.
+     * Returns source value.
+     *
+     * @return array|bool|string
      */
-    public function setBoolFilterParameters($params)
+    public function getSource()
     {
-        $this->boolFilterParams = $params;
+        return $this->source;
     }
 
     /**
-     * @param AbstractSuggester $suggester
+     * Allows to selectively load specific stored fields for each document represented by a search hit.
+     *
+     * @param array $fields
      *
      * @return Search
      */
-    public function addSuggester(AbstractSuggester $suggester)
+    public function setFields(array $fields)
     {
-        if ($this->suggesters === null) {
-            $this->suggesters = new NamedBuilderBag();
-        }
-        $this->suggesters->add($suggester);
+        $this->fields = $fields;
 
         return $this;
     }
 
     /**
-     * Returns query url parameters.
+     * Returns field value.
      *
      * @return array
      */
-    public function getQueryParams()
+    public function getFields()
     {
-        $array = [];
-
-        if ($this->scrollDuration !== null) {
-            $array['scroll'] = $this->scrollDuration;
-        }
+        return $this->fields;
+    }
 
-        if ($this->searchType !== null) {
-            $array['search_type'] = $this->searchType;
-        }
+    /**
+     * Allows to return a script evaluation (based on different fields) for each hit.
+     *
+     * @param array $scriptFields
+     *
+     * @return Search
+     */
+    public function setScriptFields($scriptFields)
+    {
+        $this->scriptFields = $scriptFields;
 
-        if ($this->preference !== null) {
-            $array['preference'] = $this->getPreference();
-        }
+        return $this;
+    }
 
-        return $array;
+    /**
+     * Returns containing script fields.
+     *
+     * @return array
+     */
+    public function getScriptFields()
+    {
+        return $this->scriptFields;
     }
 
     /**
-     * @return NamedBuilderBag
+     * Allows to highlight search results on one or more fields.
+     *
+     * @param Highlight $highlight
+     *
+     * @return Search
      */
-    public function getAggregations()
+    public function setHighlight($highlight)
     {
-        return $this->aggregations;
+        $this
+            ->getEndpoint('highlight')
+            ->addBuilder($highlight);
+
+        return $this;
     }
 
     /**
-     * @return array
+     * Returns containing highlight object.
+     *
+     * @return Highlight
      */
-    public function getBoolFilterParameters()
+    public function getHighlight()
     {
-        return $this->boolFilterParams;
+        return $this
+            ->getEndpoint('highlight')
+            ->getBuilder();
     }
 
     /**
-     * @return array
+     * Sets explain property in request body search.
+     *
+     * @param bool $explain
+     *
+     * @return Search
      */
-    public function getBoolQueryParameters()
+    public function setExplain($explain)
     {
-        return $this->boolQueryParams;
+        $this->explain = $explain;
+
+        return $this;
     }
 
     /**
+     * Returns if explain property is set in request body search.
+     *
      * @return bool
      */
     public function isExplain()
@@ -493,107 +508,187 @@ class Search
     }
 
     /**
-     * @return array
+     * Sets a stats group.
+     *
+     * @param array $stats
+     *
+     * @return Search
      */
-    public function getFields()
+    public function setStats($stats)
     {
-        return $this->fields;
+        $this->stats = $stats;
+
+        return $this;
     }
 
     /**
-     * @return BuilderInterface[]
+     * Returns a stats group.
+     *
+     * @return array
      */
-    public function getFilters()
+    public function getStats()
     {
-        return $this->filters;
+        return $this->stats;
     }
 
     /**
-     * @return int
+     * Adds aggregation into search.
+     *
+     * @param AbstractAggregation $aggregation
+     *
+     * @return Search
      */
-    public function getFrom()
+    public function addAggregation(AbstractAggregation $aggregation)
     {
-        return $this->from;
+        $this
+            ->getEndpoint('aggregations')
+            ->addBuilder($aggregation);
+
+        return $this;
     }
 
     /**
-     * @return Highlight
+     * Returns contained aggregations.
+     *
+     * @return AbstractAggregation[]
      */
-    public function getHighlight()
+    public function getAggregations()
     {
-        return $this->highlight;
+        return $this
+            ->getEndpoint('aggregations')
+            ->getBuilder();
     }
 
     /**
-     * @return BuilderInterface
+     * Adds suggester to search.
+     *
+     * @param AbstractSuggester $suggester
+     *
+     * @return Search
      */
-    public function getPostFilters()
+    public function addSuggester(AbstractSuggester $suggester)
     {
-        return $this->postFilters;
+        $this
+            ->getEndpoint('suggest')
+            ->addBuilder($suggester);
+
+        return $this;
     }
 
     /**
-     * @return array
+     * Returns all contained suggester's.
+     *
+     * @return AbstractSuggester[]
      */
-    public function getScriptFields()
+    public function getSuggesters()
     {
-        return $this->scriptFields;
+        return $this
+            ->getEndpoint('suggest')
+            ->getBuilder();
     }
 
     /**
-     * @return null|string
+     * Setter for scroll duration, effectively setting if search is scrolled or not.
+     *
+     * @param string|null $duration
+     *
+     * @return Search
      */
-    public function getScrollDuration()
+    public function setScroll($duration = self::SCROLL_DURATION)
     {
-        return $this->scrollDuration;
+        $this->scrollDuration = $duration;
+
+        return $this;
     }
 
     /**
-     * @return string
+     * Returns scroll duration.
+     *
+     * @return string|null
      */
-    public function getSearchType()
+    public function getScroll()
     {
-        return $this->searchType;
+        return $this->scrollDuration;
     }
 
     /**
-     * @return int
+     * Set search type.
+     *
+     * @param string $searchType
+     *
+     * @return Search
      */
-    public function getSize()
+    public function setSearchType($searchType)
     {
-        return $this->size;
+        $this->searchType = $searchType;
+
+        return $this;
     }
 
     /**
-     * @return Sorts
+     * Returns search type used.
+     *
+     * @return string
      */
-    public function getSorts()
+    public function getSearchType()
     {
-        return $this->sorts;
+        return $this->searchType;
     }
 
     /**
-     * @return array|bool|string
+     * Setter for preference.
+     *
+     * Controls which shard replicas to execute the search request on.
+     *
+     * @param mixed $preferenceParams Possible values:
+     *                                _primary
+     *                                _primary_first
+     *                                _local
+     *                                _only_node:xyz (xyz - node id)
+     *                                _prefer_node:xyz (xyz - node id)
+     *                                _shards:2,3 (2 and 3 specified shards)
+     *                                custom value
+     *                                string[] combination of params.
+     *
+     * @return Search
      */
-    public function getSource()
+    public function setPreference($preferenceParams)
     {
-        return $this->source;
+        if (is_string($preferenceParams)) {
+            $this->preference[] = $preferenceParams;
+        }
+
+        if (is_array($preferenceParams) && !empty($preferenceParams)) {
+            $this->preference = $preferenceParams;
+        }
+
+        return $this;
     }
 
     /**
-     * @return array
+     * Returns preference params as string.
+     *
+     * @return string
      */
-    public function getStats()
+    public function getPreference()
     {
-        return $this->stats;
+        return $this->preference ? implode(';', $this->preference) : null;
     }
 
     /**
-     * @return NamedBuilderBag
+     * Returns query url parameters.
+     *
+     * @return array
      */
-    public function getSuggesters()
+    public function getQueryParams()
     {
-        return $this->suggesters;
+        return array_filter(
+            [
+                'scroll' => $this->getScroll(),
+                'search_type' => $this->getSearchType(),
+                'preference' => $this->getPreference(),
+            ]
+        );
     }
 
     /**
@@ -601,29 +696,7 @@ class Search
      */
     public function toArray()
     {
-        /*
-         * First we check if there are some filter to add to filtered query.
-         * For now we use match all, but its gonna be changed.
-         */
-
-        if ($this->filters !== null) {
-            $filteredQuery = new FilteredQuery();
-            $filteredQuery->setFilter($this->filters);
-            $this->addQuery($filteredQuery);
-        }
-
-        $output = $this->processQueries();
-
-        if ($this->postFilters !== null) {
-            $postFilter = new PostFilter();
-            $postFilter->setFilter($this->postFilters);
-
-            $output[$postFilter->getType()] = $postFilter->toArray();
-        }
-
-        if ($this->highlight !== null) {
-            $output['highlight'] = $this->highlight->toArray();
-        }
+        $output = array_filter($this->serializer->normalize($this->endpoints));
 
         $params = [
             'from' => 'from',
@@ -633,6 +706,7 @@ class Search
             'explain' => 'explain',
             'stats' => 'stats',
             'minScore' => 'min_score',
+            'source' => '_source',
         ];
 
         foreach ($params as $field => $param) {
@@ -641,36 +715,32 @@ class Search
             }
         }
 
-        if ($this->sorts && $this->sorts->isRelevant()) {
-            $output[$this->sorts->getType()] = $this->sorts->toArray();
-        }
-
-        if ($this->source !== null) {
-            $output['_source'] = $this->source;
-        }
-
-        if ($this->aggregations !== null) {
-            $aggregationsOutput = [];
-            foreach ($this->aggregations->all() as $aggregation) {
-                $aggregationsOutput = array_merge($aggregationsOutput, $aggregation->toArray());
-            }
+        return $output;
+    }
 
-            if (!empty($aggregationsOutput)) {
-                $output['aggregations'] = $aggregationsOutput;
-            }
+    /**
+     * Returns endpoint instance.
+     *
+     * @param string $type Endpoint type.
+     *
+     * @return SearchEndpointInterface
+     */
+    private function getEndpoint($type)
+    {
+        if (!array_key_exists($type, $this->endpoints)) {
+            $this->endpoints[$type] = SearchEndpointFactory::get($type);
         }
 
-        if ($this->suggesters !== null) {
-            $suggestersOutput = [];
-            foreach ($this->suggesters->all() as $suggester) {
-                $suggestersOutput = array_merge($suggestersOutput, $suggester->toArray());
-            }
-
-            if (!empty($suggestersOutput)) {
-                $output['suggest'] = $suggestersOutput;
-            }
-        }
+        return $this->endpoints[$type];
+    }
 
-        return $output;
+    /**
+     * Destroys search endpoint.
+     *
+     * @param string $type Endpoint type.
+     */
+    private function destroyEndpoint($type)
+    {
+        unset($this->endpoints[$type]);
     }
 }