diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6fdd8fc2033fd8b2afb0b9261ff4614e19f2ee6c..891a1d89fb68302d6ba6e5fdd41cdf3530df8575 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,15 @@
 # CHANGELOG
-   
-v2.x (2016-x)
+v5.0.0 (2017-x)
 ---
-   
+- **[BC break]** Removed deprecated aggregation classes.
+- **[BC break]** Removed deprecated query classes.
+
+v2.2.1 (2017-01-26)
+---
+- Fixed function score for 2.x elastic.
+- Fixed bug in nested and reverse nested aggregations. (#173)
+- Fixed bool query key assign for some OS to avoid duplication.
+
 v2.2.0 (2016-11.11)
 ---
 - Added support for elasticsearch 5.0
@@ -67,3 +74,7 @@ v1.0.1 (2015-12-16)
 - Fixed `function_score` query options handling [#35](https://github.com/ongr-io/ElasticsearchDSL/issues/35)
 - Added Symfony 3 compatibility
 - Added support for `timeout` and `terminate_after` options in Search endpoint [#34](https://github.com/ongr-io/ElasticsearchDSL/issues/34)
+
+v1.0.0 (2015-09-14)
+---
+- First stable version, [more info here](https://github.com/ongr-io/ElasticsearchDSL/blob/v1.0.0/docs/index.md).
\ No newline at end of file
diff --git a/src/Query/BoolQuery.php b/src/Query/BoolQuery.php
index 8ee0b6c664e1c8090cfdc318ff410c78b044a63f..ff217b9fe7b970d4a9f52aac6bca6616da1a1b5c 100644
--- a/src/Query/BoolQuery.php
+++ b/src/Query/BoolQuery.php
@@ -11,119 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "bool" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class BoolQuery implements BuilderInterface
+class BoolQuery extends \ONGR\ElasticsearchDSL\Query\Compound\BoolQuery
 {
-    use ParametersTrait;
-
-    const MUST = 'must';
-    const MUST_NOT = 'must_not';
-    const SHOULD = 'should';
-    const FILTER = 'filter';
-
-    /**
-     * @var array
-     */
-    private $container = [];
-
-    /**
-     * Constructor to prepare container.
-     */
-    public function __construct()
-    {
-        $this->container = [];
-    }
-
-    /**
-     * Returns the query instances (by bool type).
-     *
-     * @param  string|null $boolType
-     *
-     * @return array
-     */
-    public function getQueries($boolType = null)
-    {
-        if ($boolType === null) {
-            $queries = [];
-
-            foreach ($this->container as $item) {
-                $queries = array_merge($queries, $item);
-            }
-
-            return $queries;
-        }
-
-        if (isset($this->container[$boolType])) {
-            return $this->container[$boolType];
-        }
-
-        return [];
-    }
-
-    /**
-     * Add BuilderInterface object to bool operator.
-     *
-     * @param BuilderInterface $query Query add to the bool.
-     * @param string           $type  Bool type. Example: must, must_not, should.
-     * @param string           $key   Key that indicates a builder id.
-     *
-     * @return string Key of added builder.
-     *
-     * @throws \UnexpectedValueException
-     */
-    public function add(BuilderInterface $query, $type = self::MUST, $key = null)
-    {
-        if (!in_array($type, [self::MUST, self::MUST_NOT, self::SHOULD, self::FILTER])) {
-            throw new \UnexpectedValueException(sprintf('The bool operator %s is not supported', $type));
-        }
-
-        if (!$key) {
-            $key = bin2hex(random_bytes(30));
-        }
-
-        $this->container[$type][$key] = $query;
-
-        return $key;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        if (count($this->container) === 1 && isset($this->container[self::MUST])
-                && count($this->container[self::MUST]) === 1) {
-            $query = reset($this->container[self::MUST]);
-
-            return $query->toArray();
-        }
-
-        $output = [];
-
-        foreach ($this->container as $boolType => $builders) {
-            /** @var BuilderInterface $builder */
-            foreach ($builders as $builder) {
-                $output[$boolType][] = $builder->toArray();
-            }
-        }
-
-        $output = $this->processArray($output);
-
-        return [$this->getType() => $output];
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'bool';
-    }
 }
diff --git a/src/Query/BoostingQuery.php b/src/Query/BoostingQuery.php
index 2e6fe64077216a6f420636c4b94ed743d14e694f..c59f367c85cba4a41a4339a5cb79aef2bdea63e1 100644
--- a/src/Query/BoostingQuery.php
+++ b/src/Query/BoostingQuery.php
@@ -11,61 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-
 /**
  * Represents Elasticsearch "boosting" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-boosting-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class BoostingQuery implements BuilderInterface
+class BoostingQuery extends \ONGR\ElasticsearchDSL\Query\Compound\BoostingQuery
 {
-    /**
-     * @var BuilderInterface
-     */
-    private $positive;
-
-    /**
-     * @var BuilderInterface
-     */
-    private $negative;
-
-    /**
-     * @var int|float
-     */
-    private $negativeBoost;
-
-    /**
-     * @param BuilderInterface $positive
-     * @param BuilderInterface $negative
-     * @param int|float        $negativeBoost
-     */
-    public function __construct(BuilderInterface $positive, BuilderInterface $negative, $negativeBoost)
-    {
-        $this->positive = $positive;
-        $this->negative = $negative;
-        $this->negativeBoost = $negativeBoost;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'boosting';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'positive' => $this->positive->toArray(),
-            'negative' => $this->negative->toArray(),
-            'negative_boost' => $this->negativeBoost,
-        ];
-
-        return [$this->getType() => $query];
-    }
 }
diff --git a/src/Query/CommonTermsQuery.php b/src/Query/CommonTermsQuery.php
index aa1dfc72a1c888190d37ba95a4d57ecefb71468e..c919c67e57eeb98e121708b65388306a566d8694 100644
--- a/src/Query/CommonTermsQuery.php
+++ b/src/Query/CommonTermsQuery.php
@@ -11,61 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "common" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-common-terms-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class CommonTermsQuery implements BuilderInterface
+class CommonTermsQuery extends \ONGR\ElasticsearchDSL\Query\FullText\CommonTermsQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string
-     */
-    private $field;
-
-    /**
-     * @var string
-     */
-    private $query;
-
-    /**
-     * @param string $field
-     * @param string $query
-     * @param array  $parameters
-     */
-    public function __construct($field, $query, array $parameters = [])
-    {
-        $this->field = $field;
-        $this->query = $query;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'common';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'query' => $this->query,
-        ];
-
-        $output = [
-            $this->field => $this->processArray($query),
-        ];
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/Compound/BoolQuery.php b/src/Query/Compound/BoolQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..4b30287e2d0517572730050ca02606161403d489
--- /dev/null
+++ b/src/Query/Compound/BoolQuery.php
@@ -0,0 +1,129 @@
+<?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\ElasticsearchDSL\Query\Compound;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "bool" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html
+ */
+class BoolQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    const MUST = 'must';
+    const MUST_NOT = 'must_not';
+    const SHOULD = 'should';
+    const FILTER = 'filter';
+
+    /**
+     * @var array
+     */
+    private $container = [];
+
+    /**
+     * Constructor to prepare container.
+     */
+    public function __construct()
+    {
+        $this->container = [];
+    }
+
+    /**
+     * Returns the query instances (by bool type).
+     *
+     * @param  string|null $boolType
+     *
+     * @return array
+     */
+    public function getQueries($boolType = null)
+    {
+        if ($boolType === null) {
+            $queries = [];
+
+            foreach ($this->container as $item) {
+                $queries = array_merge($queries, $item);
+            }
+
+            return $queries;
+        }
+
+        if (isset($this->container[$boolType])) {
+            return $this->container[$boolType];
+        }
+
+        return [];
+    }
+
+    /**
+     * Add BuilderInterface object to bool operator.
+     *
+     * @param BuilderInterface $query Query add to the bool.
+     * @param string           $type  Bool type. Example: must, must_not, should.
+     * @param string           $key   Key that indicates a builder id.
+     *
+     * @return string Key of added builder.
+     *
+     * @throws \UnexpectedValueException
+     */
+    public function add(BuilderInterface $query, $type = self::MUST, $key = null)
+    {
+        if (!in_array($type, [self::MUST, self::MUST_NOT, self::SHOULD, self::FILTER])) {
+            throw new \UnexpectedValueException(sprintf('The bool operator %s is not supported', $type));
+        }
+
+        if (!$key) {
+            $key = bin2hex(random_bytes(30));
+        }
+
+        $this->container[$type][$key] = $query;
+
+        return $key;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        if (count($this->container) === 1 && isset($this->container[self::MUST])
+                && count($this->container[self::MUST]) === 1) {
+            $query = reset($this->container[self::MUST]);
+
+            return $query->toArray();
+        }
+
+        $output = [];
+
+        foreach ($this->container as $boolType => $builders) {
+            /** @var BuilderInterface $builder */
+            foreach ($builders as $builder) {
+                $output[$boolType][] = $builder->toArray();
+            }
+        }
+
+        $output = $this->processArray($output);
+
+        return [$this->getType() => $output];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'bool';
+    }
+}
diff --git a/src/Query/Compound/BoostingQuery.php b/src/Query/Compound/BoostingQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..87d3523b3ac233d33084f7e6b4646338eb058c09
--- /dev/null
+++ b/src/Query/Compound/BoostingQuery.php
@@ -0,0 +1,71 @@
+<?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\ElasticsearchDSL\Query\Compound;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+
+/**
+ * Represents Elasticsearch "boosting" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-boosting-query.html
+ */
+class BoostingQuery implements BuilderInterface
+{
+    /**
+     * @var BuilderInterface
+     */
+    private $positive;
+
+    /**
+     * @var BuilderInterface
+     */
+    private $negative;
+
+    /**
+     * @var int|float
+     */
+    private $negativeBoost;
+
+    /**
+     * @param BuilderInterface $positive
+     * @param BuilderInterface $negative
+     * @param int|float        $negativeBoost
+     */
+    public function __construct(BuilderInterface $positive, BuilderInterface $negative, $negativeBoost)
+    {
+        $this->positive = $positive;
+        $this->negative = $negative;
+        $this->negativeBoost = $negativeBoost;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'boosting';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'positive' => $this->positive->toArray(),
+            'negative' => $this->negative->toArray(),
+            'negative_boost' => $this->negativeBoost,
+        ];
+
+        return [$this->getType() => $query];
+    }
+}
diff --git a/src/Query/Compound/ConstantScoreQuery.php b/src/Query/Compound/ConstantScoreQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..ee3373a5f48fed939b28e87d7b537572dae18f0d
--- /dev/null
+++ b/src/Query/Compound/ConstantScoreQuery.php
@@ -0,0 +1,62 @@
+<?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\ElasticsearchDSL\Query\Compound;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "constant_score" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-constant-score-query.html
+ */
+class ConstantScoreQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var BuilderInterface
+     */
+    private $query;
+
+    /**
+     * @param BuilderInterface $query
+     * @param array            $parameters
+     */
+    public function __construct(BuilderInterface $query, array $parameters = [])
+    {
+        $this->query = $query;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'constant_score';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'filter' => $this->query->toArray(),
+        ];
+
+        $output = $this->processArray($query);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/Compound/DisMaxQuery.php b/src/Query/Compound/DisMaxQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..adb77c36f5a1a46cdacd6b3d55d1fb501a966f79
--- /dev/null
+++ b/src/Query/Compound/DisMaxQuery.php
@@ -0,0 +1,76 @@
+<?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\ElasticsearchDSL\Query\Compound;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "dis_max" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-dis-max-query.html
+ */
+class DisMaxQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var BuilderInterface[]
+     */
+    private $queries = [];
+
+    /**
+     * Initializes Dis Max query.
+     *
+     * @param array $parameters
+     */
+    public function __construct(array $parameters = [])
+    {
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * Add query.
+     *
+     * @param BuilderInterface $query
+     *
+     * @return DisMaxQuery
+     */
+    public function addQuery(BuilderInterface $query)
+    {
+        $this->queries[] = $query;
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'dis_max';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [];
+        foreach ($this->queries as $type) {
+            $query[] = $type->toArray();
+        }
+        $output = $this->processArray(['queries' => $query]);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/Compound/FunctionScoreQuery.php b/src/Query/Compound/FunctionScoreQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..38e01fe892a5cd354bc525b48753b351f7c56880
--- /dev/null
+++ b/src/Query/Compound/FunctionScoreQuery.php
@@ -0,0 +1,229 @@
+<?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\ElasticsearchDSL\Query\Compound;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "function_score" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html
+ */
+class FunctionScoreQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var BuilderInterface
+     */
+    private $query;
+
+    /**
+     * @var array[]
+     */
+    private $functions;
+
+    /**
+     * @param BuilderInterface $query
+     * @param array            $parameters
+     */
+    public function __construct(BuilderInterface $query, array $parameters = [])
+    {
+        $this->query = $query;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'function_score';
+    }
+
+    /**
+     * Modifier to apply filter to the function score function.
+     *
+     * @param array            $function
+     * @param BuilderInterface $query
+     */
+    private function applyFilter(array &$function, BuilderInterface $query = null)
+    {
+        if ($query) {
+            $function['filter'] = $query->toArray();
+        }
+    }
+
+    /**
+     * Creates field_value_factor function.
+     *
+     * @param string           $field
+     * @param float            $factor
+     * @param string           $modifier
+     * @param BuilderInterface $query
+     *
+     * @return $this
+     */
+    public function addFieldValueFactorFunction($field, $factor, $modifier = 'none', BuilderInterface $query = null)
+    {
+        $function = [
+            'field_value_factor' => [
+                'field' => $field,
+                'factor' => $factor,
+                'modifier' => $modifier,
+            ],
+        ];
+
+        $this->applyFilter($function, $query);
+
+        $this->functions[] = $function;
+
+        return $this;
+    }
+
+    /**
+     * Add decay function to function score. Weight and query are optional.
+     *
+     * @param string           $type
+     * @param string           $field
+     * @param array            $function
+     * @param array            $options
+     * @param BuilderInterface $query
+     *
+     * @return $this
+     */
+    public function addDecayFunction(
+        $type,
+        $field,
+        array $function,
+        array $options = [],
+        BuilderInterface $query = null
+    ) {
+        $function = [
+            $type => array_merge(
+                [$field => $function],
+                $options
+            ),
+        ];
+
+        $this->applyFilter($function, $query);
+
+        $this->functions[] = $function;
+
+        return $this;
+    }
+
+    /**
+     * Adds function to function score without decay function. Influence search score only for specific query.
+     *
+     * @param float            $weight
+     * @param BuilderInterface $query
+     *
+     * @return $this
+     */
+    public function addWeightFunction($weight, BuilderInterface $query = null)
+    {
+        $function = [
+            'weight' => $weight,
+        ];
+
+        $this->applyFilter($function, $query);
+
+        $this->functions[] = $function;
+
+        return $this;
+    }
+
+    /**
+     * Adds random score function. Seed is optional.
+     *
+     * @param mixed            $seed
+     * @param BuilderInterface $query
+     *
+     * @return $this
+     */
+    public function addRandomFunction($seed = null, BuilderInterface $query = null)
+    {
+        $function = [
+            'random_score' => $seed ? [ 'seed' => $seed ] : new \stdClass(),
+        ];
+
+        $this->applyFilter($function, $query);
+
+        $this->functions[] = $function;
+
+        return $this;
+    }
+
+    /**
+     * Adds script score function.
+     *
+     * @param string           $script
+     * @param array            $params
+     * @param array            $options
+     * @param BuilderInterface $query
+     *
+     * @return $this
+     */
+    public function addScriptScoreFunction(
+        $script,
+        array $params = [],
+        array $options = [],
+        BuilderInterface $query = null
+    ) {
+        $function = [
+            'script_score' => array_merge(
+                [
+                    'script' => $script,
+                    'params' => $params,
+                ],
+                $options
+            ),
+        ];
+
+        $this->applyFilter($function, $query);
+
+        $this->functions[] = $function;
+
+        return $this;
+    }
+
+    /**
+     * Adds custom simple function. You can add to the array whatever you want.
+     *
+     * @param array $function
+     *
+     * @return $this
+     */
+    public function addSimpleFunction(array $function)
+    {
+        $this->functions[] = $function;
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'query' => $this->query->toArray(),
+            'functions' => $this->functions,
+        ];
+
+        $output = $this->processArray($query);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/Compound/IndicesQuery.php b/src/Query/Compound/IndicesQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..0348465274ac1ad6c0109d12c85afc1303bf2958
--- /dev/null
+++ b/src/Query/Compound/IndicesQuery.php
@@ -0,0 +1,81 @@
+<?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\ElasticsearchDSL\Query\Compound;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+
+/**
+ * Represents Elasticsearch "indices" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-indices-query.html
+ */
+class IndicesQuery implements BuilderInterface
+{
+    /**
+     * @var string[]
+     */
+    private $indices;
+
+    /**
+     * @var BuilderInterface
+     */
+    private $query;
+
+    /**
+     * @var string|BuilderInterface
+     */
+    private $noMatchQuery;
+
+    /**
+     * @param string[]         $indices
+     * @param BuilderInterface $query
+     * @param BuilderInterface $noMatchQuery
+     */
+    public function __construct($indices, $query, $noMatchQuery = null)
+    {
+        $this->indices = $indices;
+        $this->query = $query;
+        $this->noMatchQuery = $noMatchQuery;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'indices';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        if (count($this->indices) > 1) {
+            $output = ['indices' => $this->indices];
+        } else {
+            $output = ['index' => $this->indices[0]];
+        }
+
+        $output['query'] = $this->query->toArray();
+
+        if ($this->noMatchQuery !== null) {
+            if (is_a($this->noMatchQuery, 'ONGR\ElasticsearchDSL\BuilderInterface')) {
+                $output['no_match_query'] = $this->noMatchQuery->toArray();
+            } else {
+                $output['no_match_query'] = $this->noMatchQuery;
+            }
+        }
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/ConstantScoreQuery.php b/src/Query/ConstantScoreQuery.php
index 6ec11501732b21a938d47fef1cbfecd506c49ead..b0b31fd041be4e1592c17b0f46e186a2e1b80db2 100644
--- a/src/Query/ConstantScoreQuery.php
+++ b/src/Query/ConstantScoreQuery.php
@@ -11,52 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "constant_score" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-constant-score-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class ConstantScoreQuery implements BuilderInterface
+class ConstantScoreQuery extends \ONGR\ElasticsearchDSL\Query\Compound\ConstantScoreQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var BuilderInterface
-     */
-    private $query;
-
-    /**
-     * @param BuilderInterface $query
-     * @param array            $parameters
-     */
-    public function __construct(BuilderInterface $query, array $parameters = [])
-    {
-        $this->query = $query;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'constant_score';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'filter' => $this->query->toArray(),
-        ];
-
-        $output = $this->processArray($query);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/DisMaxQuery.php b/src/Query/DisMaxQuery.php
index aee0d331b7365645f70b2058d7811a94d0d232d4..0485c64e680507ce946a02c79bd01c789037fd84 100644
--- a/src/Query/DisMaxQuery.php
+++ b/src/Query/DisMaxQuery.php
@@ -11,66 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "dis_max" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-dis-max-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class DisMaxQuery implements BuilderInterface
+class DisMaxQuery extends \ONGR\ElasticsearchDSL\Query\Compound\DisMaxQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var BuilderInterface[]
-     */
-    private $queries = [];
-
-    /**
-     * Initializes Dis Max query.
-     *
-     * @param array $parameters
-     */
-    public function __construct(array $parameters = [])
-    {
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * Add query.
-     *
-     * @param BuilderInterface $query
-     *
-     * @return DisMaxQuery
-     */
-    public function addQuery(BuilderInterface $query)
-    {
-        $this->queries[] = $query;
-
-        return $this;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'dis_max';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [];
-        foreach ($this->queries as $type) {
-            $query[] = $type->toArray();
-        }
-        $output = $this->processArray(['queries' => $query]);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/ExistsQuery.php b/src/Query/ExistsQuery.php
index fd7f4de834dfa9844b0167a2919febe20ad94ce6..26227c6e7377ced654a426f7e7ba53d9d741cf62 100644
--- a/src/Query/ExistsQuery.php
+++ b/src/Query/ExistsQuery.php
@@ -11,47 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-
 /**
  * Represents Elasticsearch "exists" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class ExistsQuery implements BuilderInterface
+class ExistsQuery extends \ONGR\ElasticsearchDSL\Query\TermLevel\ExistsQuery
 {
-    /**
-     * @var string
-     */
-    private $field;
-
-    /**
-     * Constructor.
-     *
-     * @param string $field Field value
-     */
-    public function __construct($field)
-    {
-        $this->field = $field;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'exists';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        return [
-            $this->getType() => [
-                'field' => $this->field,
-            ],
-        ];
-    }
 }
diff --git a/src/Query/FullText/CommonTermsQuery.php b/src/Query/FullText/CommonTermsQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..2e31b13bf01ddaea99147560bc877459f0dd8539
--- /dev/null
+++ b/src/Query/FullText/CommonTermsQuery.php
@@ -0,0 +1,71 @@
+<?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\ElasticsearchDSL\Query\FullText;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "common" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-common-terms-query.html
+ */
+class CommonTermsQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string
+     */
+    private $field;
+
+    /**
+     * @var string
+     */
+    private $query;
+
+    /**
+     * @param string $field
+     * @param string $query
+     * @param array  $parameters
+     */
+    public function __construct($field, $query, array $parameters = [])
+    {
+        $this->field = $field;
+        $this->query = $query;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'common';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'query' => $this->query,
+        ];
+
+        $output = [
+            $this->field => $this->processArray($query),
+        ];
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/FullText/MatchPhrasePrefixQuery.php b/src/Query/FullText/MatchPhrasePrefixQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..58f8a83a9e1c600cd6126a6c10641d43f3932bb0
--- /dev/null
+++ b/src/Query/FullText/MatchPhrasePrefixQuery.php
@@ -0,0 +1,29 @@
+<?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\ElasticsearchDSL\Query\FullText;
+
+/**
+ * Represents Elasticsearch "match_phrase_prefix" query.
+ *
+ * @author Ron Rademaker
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html
+ */
+class MatchPhrasePrefixQuery extends MatchQuery
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'match_phrase_prefix';
+    }
+}
diff --git a/src/Query/FullText/MatchPhraseQuery.php b/src/Query/FullText/MatchPhraseQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..2560088f31d99b76299d761ec9ccb6e4843a1147
--- /dev/null
+++ b/src/Query/FullText/MatchPhraseQuery.php
@@ -0,0 +1,29 @@
+<?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\ElasticsearchDSL\Query\FullText;
+
+/**
+ * Represents Elasticsearch "match_phrase" query.
+ *
+ * @author Ron Rademaker
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html
+ */
+class MatchPhraseQuery extends MatchQuery
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'match_phrase';
+    }
+}
diff --git a/src/Query/FullText/MatchQuery.php b/src/Query/FullText/MatchQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..6ce6801c95c2747be4e4521515aa777a401e93f1
--- /dev/null
+++ b/src/Query/FullText/MatchQuery.php
@@ -0,0 +1,71 @@
+<?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\ElasticsearchDSL\Query\FullText;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "match" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html
+ */
+class MatchQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string
+     */
+    private $field;
+
+    /**
+     * @var string
+     */
+    private $query;
+
+    /**
+     * @param string $field
+     * @param string $query
+     * @param array  $parameters
+     */
+    public function __construct($field, $query, array $parameters = [])
+    {
+        $this->field = $field;
+        $this->query = $query;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'match';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'query' => $this->query,
+        ];
+
+        $output = [
+            $this->field => $this->processArray($query),
+        ];
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/FullText/MultiMatchQuery.php b/src/Query/FullText/MultiMatchQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..ec7f04fc2a89f3b5403793d5ef69a4a29ee88641
--- /dev/null
+++ b/src/Query/FullText/MultiMatchQuery.php
@@ -0,0 +1,70 @@
+<?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\ElasticsearchDSL\Query\FullText;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "multi_match" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html
+ */
+class MultiMatchQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var array
+     */
+    private $fields = [];
+
+    /**
+     * @var string
+     */
+    private $query;
+
+    /**
+     * @param array  $fields
+     * @param string $query
+     * @param array  $parameters
+     */
+    public function __construct(array $fields, $query, array $parameters = [])
+    {
+        $this->fields = $fields;
+        $this->query = $query;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'multi_match';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'fields' => $this->fields,
+            'query' => $this->query,
+        ];
+
+        $output = $this->processArray($query);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/FullText/QueryStringQuery.php b/src/Query/FullText/QueryStringQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..29eda3fafa17efced0b833bb1fc5151707f31338
--- /dev/null
+++ b/src/Query/FullText/QueryStringQuery.php
@@ -0,0 +1,62 @@
+<?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\ElasticsearchDSL\Query\FullText;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "query_string" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html
+ */
+class QueryStringQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string The actual query to be parsed.
+     */
+    private $query;
+
+    /**
+     * @param string $query
+     * @param array  $parameters
+     */
+    public function __construct($query, array $parameters = [])
+    {
+        $this->query = $query;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'query_string';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'query' => $this->query,
+        ];
+
+        $output = $this->processArray($query);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/FullText/SimpleQueryStringQuery.php b/src/Query/FullText/SimpleQueryStringQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..976ffceb1cca64a05fdcd6aa6d7f6c355092fef6
--- /dev/null
+++ b/src/Query/FullText/SimpleQueryStringQuery.php
@@ -0,0 +1,62 @@
+<?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\ElasticsearchDSL\Query\FullText;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "simple_query_string" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html
+ */
+class SimpleQueryStringQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string The actual query to be parsed.
+     */
+    private $query;
+
+    /**
+     * @param string $query
+     * @param array  $parameters
+     */
+    public function __construct($query, array $parameters = [])
+    {
+        $this->query = $query;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'simple_query_string';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'query' => $this->query,
+        ];
+
+        $output = $this->processArray($query);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/FunctionScoreQuery.php b/src/Query/FunctionScoreQuery.php
index 1519e4d0080c9cd5098d6f9a671f919426d6687f..3657e6e89238156df4db8992693d2137f3a37abc 100644
--- a/src/Query/FunctionScoreQuery.php
+++ b/src/Query/FunctionScoreQuery.php
@@ -11,228 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "function_score" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class FunctionScoreQuery implements BuilderInterface
+class FunctionScoreQuery extends \ONGR\ElasticsearchDSL\Query\Compound\FunctionScoreQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var BuilderInterface
-     */
-    private $query;
-
-    /**
-     * @var array[]
-     */
-    private $functions;
-
-    /**
-     * @param BuilderInterface $query
-     * @param array            $parameters
-     */
-    public function __construct(BuilderInterface $query, array $parameters = [])
-    {
-        $this->query = $query;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'function_score';
-    }
-
-    /**
-     * Modifier to apply filter to the function score function.
-     *
-     * @param array            $function
-     * @param BuilderInterface $query
-     */
-    private function applyFilter(array &$function, BuilderInterface $query = null)
-    {
-        if ($query) {
-            $function['filter'] = $query->toArray();
-        }
-    }
-
-    /**
-     * Creates field_value_factor function.
-     *
-     * @param string           $field
-     * @param float            $factor
-     * @param string           $modifier
-     * @param BuilderInterface $query
-     *
-     * @return $this
-     */
-    public function addFieldValueFactorFunction($field, $factor, $modifier = 'none', BuilderInterface $query = null)
-    {
-        $function = [
-            'field_value_factor' => [
-                'field' => $field,
-                'factor' => $factor,
-                'modifier' => $modifier,
-            ],
-        ];
-
-        $this->applyFilter($function, $query);
-
-        $this->functions[] = $function;
-
-        return $this;
-    }
-
-    /**
-     * Add decay function to function score. Weight and query are optional.
-     *
-     * @param string           $type
-     * @param string           $field
-     * @param array            $function
-     * @param array            $options
-     * @param BuilderInterface $query
-     *
-     * @return $this
-     */
-    public function addDecayFunction(
-        $type,
-        $field,
-        array $function,
-        array $options = [],
-        BuilderInterface $query = null
-    ) {
-        $function = [
-            $type => array_merge(
-                [$field => $function],
-                $options
-            ),
-        ];
-
-        $this->applyFilter($function, $query);
-
-        $this->functions[] = $function;
-
-        return $this;
-    }
-
-    /**
-     * Adds function to function score without decay function. Influence search score only for specific query.
-     *
-     * @param float            $weight
-     * @param BuilderInterface $query
-     *
-     * @return $this
-     */
-    public function addWeightFunction($weight, BuilderInterface $query = null)
-    {
-        $function = [
-            'weight' => $weight,
-        ];
-
-        $this->applyFilter($function, $query);
-
-        $this->functions[] = $function;
-
-        return $this;
-    }
-
-    /**
-     * Adds random score function. Seed is optional.
-     *
-     * @param mixed            $seed
-     * @param BuilderInterface $query
-     *
-     * @return $this
-     */
-    public function addRandomFunction($seed = null, BuilderInterface $query = null)
-    {
-        $function = [
-            'random_score' => $seed ? [ 'seed' => $seed ] : new \stdClass(),
-        ];
-
-        $this->applyFilter($function, $query);
-
-        $this->functions[] = $function;
-
-        return $this;
-    }
-
-    /**
-     * Adds script score function.
-     *
-     * @param string           $script
-     * @param array            $params
-     * @param array            $options
-     * @param BuilderInterface $query
-     *
-     * @return $this
-     */
-    public function addScriptScoreFunction(
-        $script,
-        array $params = [],
-        array $options = [],
-        BuilderInterface $query = null
-    ) {
-        if (count($params) > 0) {
-            $options = array_merge(
-                ['params' => $params],
-                $options
-            );
-        }
-
-        $function = [
-            'script_score' => [
-                'script' => array_merge(
-                    [
-                        'lang' => 'painless',
-                        'inline' => $script
-                    ],
-                    $options
-                )
-            ]
-        ];
-
-        $this->applyFilter($function, $query);
-
-        $this->functions[] = $function;
-
-        return $this;
-    }
-
-    /**
-     * Adds custom simple function. You can add to the array whatever you want.
-     *
-     * @param array $function
-     *
-     * @return $this
-     */
-    public function addSimpleFunction(array $function)
-    {
-        $this->functions[] = $function;
-
-        return $this;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'query' => $this->query->toArray(),
-            'functions' => $this->functions,
-        ];
-
-        $output = $this->processArray($query);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/FuzzyQuery.php b/src/Query/FuzzyQuery.php
index c5feb0026e81180347d81378a42005f7782a9f4a..81bf38f4fce0c91d198773ad2e2f0843e09ccbf0 100644
--- a/src/Query/FuzzyQuery.php
+++ b/src/Query/FuzzyQuery.php
@@ -11,61 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "fuzzy" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-fuzzy-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class FuzzyQuery implements BuilderInterface
+class FuzzyQuery extends \ONGR\ElasticsearchDSL\Query\TermLevel\FuzzyQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string
-     */
-    private $field;
-
-    /**
-     * @var string
-     */
-    private $value;
-
-    /**
-     * @param string $field
-     * @param string $value
-     * @param array  $parameters
-     */
-    public function __construct($field, $value, array $parameters = [])
-    {
-        $this->field = $field;
-        $this->value = $value;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'fuzzy';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'value' => $this->value,
-        ];
-
-        $output = [
-            $this->field => $this->processArray($query),
-        ];
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/Geo/GeoBoundingBoxQuery.php b/src/Query/Geo/GeoBoundingBoxQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..1429cfad1670abe888294e590b68dbffb884364b
--- /dev/null
+++ b/src/Query/Geo/GeoBoundingBoxQuery.php
@@ -0,0 +1,85 @@
+<?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\ElasticsearchDSL\Query\Geo;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "geo_bounding_box" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-bounding-box-query.html
+ */
+class GeoBoundingBoxQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var array
+     */
+    private $values;
+
+    /**
+     * @var string
+     */
+    private $field;
+
+    /**
+     * @param string $field
+     * @param array  $values
+     * @param array  $parameters
+     */
+    public function __construct($field, $values, array $parameters = [])
+    {
+        $this->field = $field;
+        $this->values = $values;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'geo_bounding_box';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        if (count($this->values) === 2) {
+            $query = [
+                $this->field => [
+                    'top_left' => $this->values[0],
+                    'bottom_right' => $this->values[1],
+                ],
+            ];
+        } elseif (count($this->values) === 4) {
+            $query = [
+                $this->field => [
+                    'top' => $this->values[0],
+                    'left' => $this->values[1],
+                    'bottom' => $this->values[2],
+                    'right' => $this->values[3],
+                ],
+            ];
+        } else {
+            throw new \LogicException('Geo Bounding Box filter must have 2 or 4 geo points set.');
+        }
+
+        $output = $this->processArray($query);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/Geo/GeoDistanceQuery.php b/src/Query/Geo/GeoDistanceQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..03cf202181eecea6540391ecd186784484042e32
--- /dev/null
+++ b/src/Query/Geo/GeoDistanceQuery.php
@@ -0,0 +1,77 @@
+<?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\ElasticsearchDSL\Query\Geo;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "geo_distance" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-query.html
+ */
+class GeoDistanceQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string
+     */
+    private $field;
+
+    /**
+     * @var string
+     */
+    private $distance;
+
+    /**
+     * @var mixed
+     */
+    private $location;
+
+    /**
+     * @param string $field
+     * @param string $distance
+     * @param mixed  $location
+     * @param array  $parameters
+     */
+    public function __construct($field, $distance, $location, array $parameters = [])
+    {
+        $this->field = $field;
+        $this->distance = $distance;
+        $this->location = $location;
+
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'geo_distance';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'distance' => $this->distance,
+            $this->field => $this->location,
+        ];
+        $output = $this->processArray($query);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/Geo/GeoDistanceRangeQuery.php b/src/Query/Geo/GeoDistanceRangeQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..8cced0c46a33eea235edb06872764709c5e62193
--- /dev/null
+++ b/src/Query/Geo/GeoDistanceRangeQuery.php
@@ -0,0 +1,74 @@
+<?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\ElasticsearchDSL\Query\Geo;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "geo_distance_range" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-range-query.html
+ */
+class GeoDistanceRangeQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string
+     */
+    private $field;
+
+    /**
+     * @var array
+     */
+    private $range;
+
+    /**
+     * @var mixed
+     */
+    private $location;
+
+    /**
+     * @param string $field
+     * @param array  $range
+     * @param mixed  $location
+     * @param array  $parameters
+     */
+    public function __construct($field, $range, $location, array $parameters = [])
+    {
+        $this->field = $field;
+        $this->range = $range;
+        $this->location = $location;
+
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'geo_distance_range';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = $this->range + [$this->field => $this->location];
+        $output = $this->processArray($query);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/Geo/GeoPolygonQuery.php b/src/Query/Geo/GeoPolygonQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..51a9c4eab47fe3c9dd77b6f33657fd6cda8d0e89
--- /dev/null
+++ b/src/Query/Geo/GeoPolygonQuery.php
@@ -0,0 +1,66 @@
+<?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\ElasticsearchDSL\Query\Geo;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "geo_polygon" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-polygon-query.html
+ */
+class GeoPolygonQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string
+     */
+    private $field;
+
+    /**
+     * @var array
+     */
+    private $points;
+
+    /**
+     * @param string $field
+     * @param array  $points
+     * @param array  $parameters
+     */
+    public function __construct($field, array $points = [], array $parameters = [])
+    {
+        $this->field = $field;
+        $this->points = $points;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'geo_polygon';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [$this->field => ['points' => $this->points]];
+        $output = $this->processArray($query);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/Geo/GeoShapeQuery.php b/src/Query/Geo/GeoShapeQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..9e51537a4f0404cb3df287eb269ada244646a0da
--- /dev/null
+++ b/src/Query/Geo/GeoShapeQuery.php
@@ -0,0 +1,102 @@
+<?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\ElasticsearchDSL\Query\Geo;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "geo_shape" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-shape-query.html
+ */
+class GeoShapeQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var array
+     */
+    private $fields = [];
+
+    /**
+     * @param array $parameters
+     */
+    public function __construct(array $parameters = [])
+    {
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'geo_shape';
+    }
+
+    /**
+     * Add geo-shape provided filter.
+     *
+     * @param string $field       Field name.
+     * @param string $type        Shape type.
+     * @param array  $coordinates Shape coordinates.
+     * @param array  $parameters  Additional parameters.
+     */
+    public function addShape($field, $type, array $coordinates, array $parameters = [])
+    {
+        $filter = array_merge(
+            $parameters,
+            [
+                'type' => $type,
+                'coordinates' => $coordinates,
+            ]
+        );
+
+        $this->fields[$field]['shape'] = $filter;
+    }
+
+    /**
+     * Add geo-shape pre-indexed filter.
+     *
+     * @param string $field      Field name.
+     * @param string $id         The ID of the document that containing the pre-indexed shape.
+     * @param string $type       Name of the index where the pre-indexed shape is.
+     * @param string $index      Index type where the pre-indexed shape is.
+     * @param string $path       The field specified as path containing the pre-indexed shape.
+     * @param array  $parameters Additional parameters.
+     */
+    public function addPreIndexedShape($field, $id, $type, $index, $path, array $parameters = [])
+    {
+        $filter = array_merge(
+            $parameters,
+            [
+                'id' => $id,
+                'type' => $type,
+                'index' => $index,
+                'path' => $path,
+            ]
+        );
+
+        $this->fields[$field]['indexed_shape'] = $filter;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $output = $this->processArray($this->fields);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/GeoBoundingBoxQuery.php b/src/Query/GeoBoundingBoxQuery.php
index 2940eb7ba71571e81b2c93468fe642578a98f56b..7e00821379df3224dda4494d3978f3ecffb46f43 100644
--- a/src/Query/GeoBoundingBoxQuery.php
+++ b/src/Query/GeoBoundingBoxQuery.php
@@ -11,75 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "geo_bounding_box" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-bounding-box-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class GeoBoundingBoxQuery implements BuilderInterface
+class GeoBoundingBoxQuery extends \ONGR\ElasticsearchDSL\Query\Geo\GeoBoundingBoxQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var array
-     */
-    private $values;
-
-    /**
-     * @var string
-     */
-    private $field;
-
-    /**
-     * @param string $field
-     * @param array  $values
-     * @param array  $parameters
-     */
-    public function __construct($field, $values, array $parameters = [])
-    {
-        $this->field = $field;
-        $this->values = $values;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'geo_bounding_box';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        if (count($this->values) === 2) {
-            $query = [
-                $this->field => [
-                    'top_left' => $this->values[0],
-                    'bottom_right' => $this->values[1],
-                ],
-            ];
-        } elseif (count($this->values) === 4) {
-            $query = [
-                $this->field => [
-                    'top' => $this->values[0],
-                    'left' => $this->values[1],
-                    'bottom' => $this->values[2],
-                    'right' => $this->values[3],
-                ],
-            ];
-        } else {
-            throw new \LogicException('Geo Bounding Box filter must have 2 or 4 geo points set.');
-        }
-
-        $output = $this->processArray($query);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/GeoDistanceQuery.php b/src/Query/GeoDistanceQuery.php
index d1241791c686ddfb21af251a4ba9910cf33f4899..eca616a5b6273ccc4e13325254bd504ab12f53f9 100644
--- a/src/Query/GeoDistanceQuery.php
+++ b/src/Query/GeoDistanceQuery.php
@@ -11,67 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "geo_distance" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class GeoDistanceQuery implements BuilderInterface
+class GeoDistanceQuery extends \ONGR\ElasticsearchDSL\Query\Geo\GeoDistanceQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string
-     */
-    private $field;
-
-    /**
-     * @var string
-     */
-    private $distance;
-
-    /**
-     * @var mixed
-     */
-    private $location;
-
-    /**
-     * @param string $field
-     * @param string $distance
-     * @param mixed  $location
-     * @param array  $parameters
-     */
-    public function __construct($field, $distance, $location, array $parameters = [])
-    {
-        $this->field = $field;
-        $this->distance = $distance;
-        $this->location = $location;
-
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'geo_distance';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'distance' => $this->distance,
-            $this->field => $this->location,
-        ];
-        $output = $this->processArray($query);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/GeoDistanceRangeQuery.php b/src/Query/GeoDistanceRangeQuery.php
index ef3544d9bf91c474a356a0e2bade3614e8665193..d5457ac96541b3fe15f396f44cff5116dca3f1cf 100644
--- a/src/Query/GeoDistanceRangeQuery.php
+++ b/src/Query/GeoDistanceRangeQuery.php
@@ -11,64 +11,11 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "geo_distance_range" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-range-query.html
  */
-class GeoDistanceRangeQuery implements BuilderInterface
+class GeoDistanceRangeQuery extends \ONGR\ElasticsearchDSL\Query\Geo\GeoDistanceRangeQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string
-     */
-    private $field;
-
-    /**
-     * @var array
-     */
-    private $range;
-
-    /**
-     * @var mixed
-     */
-    private $location;
-
-    /**
-     * @param string $field
-     * @param array  $range
-     * @param mixed  $location
-     * @param array  $parameters
-     */
-    public function __construct($field, $range, $location, array $parameters = [])
-    {
-        $this->field = $field;
-        $this->range = $range;
-        $this->location = $location;
-
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'geo_distance_range';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = $this->range + [$this->field => $this->location];
-        $output = $this->processArray($query);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/GeoPolygonQuery.php b/src/Query/GeoPolygonQuery.php
index eecf0e4db1dc71ffa14d15328b9fa4e29b1ec17a..3bc9158bbb69f0dd3f9178af024dd20c521b031f 100644
--- a/src/Query/GeoPolygonQuery.php
+++ b/src/Query/GeoPolygonQuery.php
@@ -11,56 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "geo_polygon" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-polygon-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class GeoPolygonQuery implements BuilderInterface
+class GeoPolygonQuery extends \ONGR\ElasticsearchDSL\Query\Geo\GeoPolygonQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string
-     */
-    private $field;
-
-    /**
-     * @var array
-     */
-    private $points;
-
-    /**
-     * @param string $field
-     * @param array  $points
-     * @param array  $parameters
-     */
-    public function __construct($field, array $points = [], array $parameters = [])
-    {
-        $this->field = $field;
-        $this->points = $points;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'geo_polygon';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [$this->field => ['points' => $this->points]];
-        $output = $this->processArray($query);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/GeoShapeQuery.php b/src/Query/GeoShapeQuery.php
index ae481db123e6a04260fefd243d8b2f8e54108138..02efa21fbef46a81ceffae2f867e449508473a50 100644
--- a/src/Query/GeoShapeQuery.php
+++ b/src/Query/GeoShapeQuery.php
@@ -11,92 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "geo_shape" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-shape-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class GeoShapeQuery implements BuilderInterface
+class GeoShapeQuery extends \ONGR\ElasticsearchDSL\Query\Geo\GeoShapeQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var array
-     */
-    private $fields = [];
-
-    /**
-     * @param array $parameters
-     */
-    public function __construct(array $parameters = [])
-    {
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'geo_shape';
-    }
-
-    /**
-     * Add geo-shape provided filter.
-     *
-     * @param string $field       Field name.
-     * @param string $type        Shape type.
-     * @param array  $coordinates Shape coordinates.
-     * @param array  $parameters  Additional parameters.
-     */
-    public function addShape($field, $type, array $coordinates, array $parameters = [])
-    {
-        $filter = array_merge(
-            $parameters,
-            [
-                'type' => $type,
-                'coordinates' => $coordinates,
-            ]
-        );
-
-        $this->fields[$field]['shape'] = $filter;
-    }
-
-    /**
-     * Add geo-shape pre-indexed filter.
-     *
-     * @param string $field      Field name.
-     * @param string $id         The ID of the document that containing the pre-indexed shape.
-     * @param string $type       Name of the index where the pre-indexed shape is.
-     * @param string $index      Index type where the pre-indexed shape is.
-     * @param string $path       The field specified as path containing the pre-indexed shape.
-     * @param array  $parameters Additional parameters.
-     */
-    public function addPreIndexedShape($field, $id, $type, $index, $path, array $parameters = [])
-    {
-        $filter = array_merge(
-            $parameters,
-            [
-                'id' => $id,
-                'type' => $type,
-                'index' => $index,
-                'path' => $path,
-            ]
-        );
-
-        $this->fields[$field]['indexed_shape'] = $filter;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $output = $this->processArray($this->fields);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/GeohashCellQuery.php b/src/Query/GeohashCellQuery.php
index 9aa15c7b8013eafbfbcb2d62a81bf1f0d3262981..d792507e8379b6a0b87a3f9d9a06995c45b39551 100644
--- a/src/Query/GeohashCellQuery.php
+++ b/src/Query/GeohashCellQuery.php
@@ -18,6 +18,7 @@ use ONGR\ElasticsearchDSL\ParametersTrait;
  * Represents Elasticsearch "geohash_cell" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geohash-cell-query.html
+ * @deprecated Use geohash_grid aggregation instead.
  */
 class GeohashCellQuery implements BuilderInterface
 {
diff --git a/src/Query/HasChildQuery.php b/src/Query/HasChildQuery.php
index 9e5044e53864db625c5a88d900f1ad5f260b4c20..f231cfcac838dd17a046dd4ac67dc4e2ea24d432 100644
--- a/src/Query/HasChildQuery.php
+++ b/src/Query/HasChildQuery.php
@@ -11,60 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "has_child" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-child-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class HasChildQuery implements BuilderInterface
+class HasChildQuery extends \ONGR\ElasticsearchDSL\Query\Joining\HasChildQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string
-     */
-    private $type;
-
-    /**
-     * @var BuilderInterface
-     */
-    private $query;
-
-    /**
-     * @param string           $type
-     * @param BuilderInterface $query
-     * @param array            $parameters
-     */
-    public function __construct($type, BuilderInterface $query, array $parameters = [])
-    {
-        $this->type = $type;
-        $this->query = $query;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'has_child';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'type' => $this->type,
-            'query' => $this->query->toArray(),
-        ];
-
-        $output = $this->processArray($query);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/HasParentQuery.php b/src/Query/HasParentQuery.php
index c57bca4eb31e137eabe6fcc7ee2896e976d7e400..490a43d50912b51bf393c821b2a6ea3aafe2aeb6 100644
--- a/src/Query/HasParentQuery.php
+++ b/src/Query/HasParentQuery.php
@@ -11,60 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "has_parent" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-parent-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class HasParentQuery implements BuilderInterface
+class HasParentQuery extends \ONGR\ElasticsearchDSL\Query\Joining\HasParentQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string
-     */
-    private $parentType;
-
-    /**
-     * @var BuilderInterface
-     */
-    private $query;
-
-    /**
-     * @param string           $parentType
-     * @param BuilderInterface $query
-     * @param array            $parameters
-     */
-    public function __construct($parentType, BuilderInterface $query, array $parameters = [])
-    {
-        $this->parentType = $parentType;
-        $this->query = $query;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'has_parent';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'parent_type' => $this->parentType,
-            'query' => $this->query->toArray(),
-        ];
-
-        $output = $this->processArray($query);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/IdsQuery.php b/src/Query/IdsQuery.php
index fa55b73e14decfc7a427a807244af73b657e0416..bec057699aa3336ef40be552e6bbbaa7ced4140f 100644
--- a/src/Query/IdsQuery.php
+++ b/src/Query/IdsQuery.php
@@ -11,52 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "ids" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-ids-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class IdsQuery implements BuilderInterface
+class IdsQuery extends \ONGR\ElasticsearchDSL\Query\TermLevel\IdsQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var array
-     */
-    private $values;
-
-    /**
-     * @param array $values
-     * @param array $parameters
-     */
-    public function __construct(array $values, array $parameters = [])
-    {
-        $this->values = $values;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'ids';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'values' => $this->values,
-        ];
-
-        $output = $this->processArray($query);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/IndicesQuery.php b/src/Query/IndicesQuery.php
index 30160b7b0b5e6a9bce48fb3082bbf647c8855691..8244aaf0a2cab02631f437218e4c887548b2b61b 100644
--- a/src/Query/IndicesQuery.php
+++ b/src/Query/IndicesQuery.php
@@ -11,71 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-
 /**
  * Represents Elasticsearch "indices" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-indices-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class IndicesQuery implements BuilderInterface
+class IndicesQuery extends \ONGR\ElasticsearchDSL\Query\Compound\IndicesQuery
 {
-    /**
-     * @var string[]
-     */
-    private $indices;
-
-    /**
-     * @var BuilderInterface
-     */
-    private $query;
-
-    /**
-     * @var string|BuilderInterface
-     */
-    private $noMatchQuery;
-
-    /**
-     * @param string[]         $indices
-     * @param BuilderInterface $query
-     * @param BuilderInterface $noMatchQuery
-     */
-    public function __construct($indices, $query, $noMatchQuery = null)
-    {
-        $this->indices = $indices;
-        $this->query = $query;
-        $this->noMatchQuery = $noMatchQuery;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'indices';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        if (count($this->indices) > 1) {
-            $output = ['indices' => $this->indices];
-        } else {
-            $output = ['index' => $this->indices[0]];
-        }
-
-        $output['query'] = $this->query->toArray();
-
-        if ($this->noMatchQuery !== null) {
-            if (is_a($this->noMatchQuery, 'ONGR\ElasticsearchDSL\BuilderInterface')) {
-                $output['no_match_query'] = $this->noMatchQuery->toArray();
-            } else {
-                $output['no_match_query'] = $this->noMatchQuery;
-            }
-        }
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/Joining/HasChildQuery.php b/src/Query/Joining/HasChildQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..4682f8c5f4913276c1859510d3d2e206e13ca851
--- /dev/null
+++ b/src/Query/Joining/HasChildQuery.php
@@ -0,0 +1,70 @@
+<?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\ElasticsearchDSL\Query\Joining;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "has_child" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-child-query.html
+ */
+class HasChildQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string
+     */
+    private $type;
+
+    /**
+     * @var BuilderInterface
+     */
+    private $query;
+
+    /**
+     * @param string           $type
+     * @param BuilderInterface $query
+     * @param array            $parameters
+     */
+    public function __construct($type, BuilderInterface $query, array $parameters = [])
+    {
+        $this->type = $type;
+        $this->query = $query;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'has_child';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'type' => $this->type,
+            'query' => $this->query->toArray(),
+        ];
+
+        $output = $this->processArray($query);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/Joining/HasParentQuery.php b/src/Query/Joining/HasParentQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..a575639b5048990432f10c3da2b4fd0a7bc97e86
--- /dev/null
+++ b/src/Query/Joining/HasParentQuery.php
@@ -0,0 +1,70 @@
+<?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\ElasticsearchDSL\Query\Joining;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "has_parent" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-parent-query.html
+ */
+class HasParentQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string
+     */
+    private $parentType;
+
+    /**
+     * @var BuilderInterface
+     */
+    private $query;
+
+    /**
+     * @param string           $parentType
+     * @param BuilderInterface $query
+     * @param array            $parameters
+     */
+    public function __construct($parentType, BuilderInterface $query, array $parameters = [])
+    {
+        $this->parentType = $parentType;
+        $this->query = $query;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'has_parent';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'parent_type' => $this->parentType,
+            'query' => $this->query->toArray(),
+        ];
+
+        $output = $this->processArray($query);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/Joining/NestedQuery.php b/src/Query/Joining/NestedQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..4db5960a63e0948b47bccada85f82699535d1da9
--- /dev/null
+++ b/src/Query/Joining/NestedQuery.php
@@ -0,0 +1,70 @@
+<?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\ElasticsearchDSL\Query\Joining;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "nested" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-query.html
+ */
+class NestedQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string
+     */
+    private $path;
+
+    /**
+     * @var BuilderInterface
+     */
+    private $query;
+
+    /**
+     * @param string           $path
+     * @param BuilderInterface $query
+     * @param array            $parameters
+     */
+    public function __construct($path, BuilderInterface $query, array $parameters = [])
+    {
+        $this->path = $path;
+        $this->query = $query;
+        $this->parameters = $parameters;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'nested';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        return [
+            $this->getType() => $this->processArray(
+                [
+                    'path' => $this->path,
+                    'query' => $this->query->toArray(),
+                ]
+            )
+        ];
+    }
+}
diff --git a/src/Query/MatchPhrasePrefixQuery.php b/src/Query/MatchPhrasePrefixQuery.php
index 8d2d61cd4c91cee51210d840c3e7ccb3aa43b141..d6a1a5d38990a395dc19448533cf2fe414e33459 100644
--- a/src/Query/MatchPhrasePrefixQuery.php
+++ b/src/Query/MatchPhrasePrefixQuery.php
@@ -14,16 +14,10 @@ namespace ONGR\ElasticsearchDSL\Query;
 /**
  * Represents Elasticsearch "match_phrase_prefix" query.
  *
- * @author Ron Rademaker
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class MatchPhrasePrefixQuery extends MatchQuery
+class MatchPhrasePrefixQuery extends \ONGR\ElasticsearchDSL\Query\FullText\MatchPhrasePrefixQuery
 {
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'match_phrase_prefix';
-    }
 }
diff --git a/src/Query/MatchPhraseQuery.php b/src/Query/MatchPhraseQuery.php
index e6f222dffc33f3aa139f8fa36dadd5a2b01c97b8..52a1278f61fa94bb7434e6ec7aac68fc94ad0dda 100644
--- a/src/Query/MatchPhraseQuery.php
+++ b/src/Query/MatchPhraseQuery.php
@@ -16,14 +16,10 @@ namespace ONGR\ElasticsearchDSL\Query;
  *
  * @author Ron Rademaker
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
+ *
  */
-class MatchPhraseQuery extends MatchQuery
+class MatchPhraseQuery extends \ONGR\ElasticsearchDSL\Query\FullText\MatchPhraseQuery
 {
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'match_phrase';
-    }
 }
diff --git a/src/Query/MatchQuery.php b/src/Query/MatchQuery.php
index 0bc220e643bd73a6108c5ed25469eb66731468e7..98f19ab1ba366089dac400657d91992a3e2998eb 100644
--- a/src/Query/MatchQuery.php
+++ b/src/Query/MatchQuery.php
@@ -11,61 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "match" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class MatchQuery implements BuilderInterface
+class MatchQuery extends \ONGR\ElasticsearchDSL\Query\FullText\MatchQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string
-     */
-    private $field;
-
-    /**
-     * @var string
-     */
-    private $query;
-
-    /**
-     * @param string $field
-     * @param string $query
-     * @param array  $parameters
-     */
-    public function __construct($field, $query, array $parameters = [])
-    {
-        $this->field = $field;
-        $this->query = $query;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'match';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'query' => $this->query,
-        ];
-
-        $output = [
-            $this->field => $this->processArray($query),
-        ];
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/MoreLikeThisQuery.php b/src/Query/MoreLikeThisQuery.php
index 7be6953e9fc40a6eff2d8b722ad40a7cdedf7f65..351accd29ef0112f064f8a9b93e3a5c49c6b0605 100644
--- a/src/Query/MoreLikeThisQuery.php
+++ b/src/Query/MoreLikeThisQuery.php
@@ -11,54 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "more_like_this" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-mlt-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class MoreLikeThisQuery implements BuilderInterface
+class MoreLikeThisQuery extends \ONGR\ElasticsearchDSL\Query\Specialized\MoreLikeThisQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string The text to find documents like it, required if ids or docs are not specified.
-     */
-    private $like;
-
-    /**
-     * @param string $like
-     * @param array  $parameters
-     */
-    public function __construct($like, array $parameters = [])
-    {
-        $this->like = $like;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'more_like_this';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [];
-
-        if (($this->hasParameter('ids') === false) || ($this->hasParameter('docs') === false)) {
-            $query['like'] = $this->like;
-        }
-
-        $output = $this->processArray($query);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/MultiMatchQuery.php b/src/Query/MultiMatchQuery.php
index 35d0eec90b8f6f55371d0989e23b63ccdd2b8e7b..63dcd3f73fbabd4bf75af29f012cb9343fb5447e 100644
--- a/src/Query/MultiMatchQuery.php
+++ b/src/Query/MultiMatchQuery.php
@@ -11,60 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "multi_match" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class MultiMatchQuery implements BuilderInterface
+class MultiMatchQuery extends \ONGR\ElasticsearchDSL\Query\FullText\MultiMatchQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var array
-     */
-    private $fields = [];
-
-    /**
-     * @var string
-     */
-    private $query;
-
-    /**
-     * @param array  $fields
-     * @param string $query
-     * @param array  $parameters
-     */
-    public function __construct(array $fields, $query, array $parameters = [])
-    {
-        $this->fields = $fields;
-        $this->query = $query;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'multi_match';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'fields' => $this->fields,
-            'query' => $this->query,
-        ];
-
-        $output = $this->processArray($query);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/NestedQuery.php b/src/Query/NestedQuery.php
index 0b020c9d4b310c669ae134daf24705eb7a422428..8080859a679186acf4bd4d9fb25d1286a2a77fd8 100644
--- a/src/Query/NestedQuery.php
+++ b/src/Query/NestedQuery.php
@@ -11,60 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "nested" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class NestedQuery implements BuilderInterface
+class NestedQuery extends \ONGR\ElasticsearchDSL\Query\Joining\NestedQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string
-     */
-    private $path;
-
-    /**
-     * @var BuilderInterface
-     */
-    private $query;
-
-    /**
-     * @param string           $path
-     * @param BuilderInterface $query
-     * @param array            $parameters
-     */
-    public function __construct($path, BuilderInterface $query, array $parameters = [])
-    {
-        $this->path = $path;
-        $this->query = $query;
-        $this->parameters = $parameters;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'nested';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        return [
-            $this->getType() => $this->processArray(
-                [
-                    'path' => $this->path,
-                    'query' => $this->query->toArray(),
-                ]
-            )
-        ];
-    }
 }
diff --git a/src/Query/PrefixQuery.php b/src/Query/PrefixQuery.php
index 903218fcc8460937f4665da1cbe95c4b6c47c329..1d1f0f104526f363b4504028809431db9a56c381 100644
--- a/src/Query/PrefixQuery.php
+++ b/src/Query/PrefixQuery.php
@@ -11,61 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "prefix" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class PrefixQuery implements BuilderInterface
+class PrefixQuery extends \ONGR\ElasticsearchDSL\Query\TermLevel\PrefixQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string
-     */
-    protected $field;
-
-    /**
-     * @var string
-     */
-    protected $value;
-
-    /**
-     * @param string $field      Field name.
-     * @param string $value      Value.
-     * @param array  $parameters Optional parameters.
-     */
-    public function __construct($field, $value, array $parameters = [])
-    {
-        $this->field = $field;
-        $this->value = $value;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'prefix';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'value' => $this->value,
-        ];
-
-        $output = [
-            $this->field => $this->processArray($query),
-        ];
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/QueryStringQuery.php b/src/Query/QueryStringQuery.php
index 3a8cb524f078d5d18c4ea362b99445fc747d66a8..3a3828ec96f8e66b532175720a0c09fae98ae1c4 100644
--- a/src/Query/QueryStringQuery.php
+++ b/src/Query/QueryStringQuery.php
@@ -11,52 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "query_string" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class QueryStringQuery implements BuilderInterface
+class QueryStringQuery extends \ONGR\ElasticsearchDSL\Query\FullText\QueryStringQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string The actual query to be parsed.
-     */
-    private $query;
-
-    /**
-     * @param string $query
-     * @param array  $parameters
-     */
-    public function __construct($query, array $parameters = [])
-    {
-        $this->query = $query;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'query_string';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'query' => $this->query,
-        ];
-
-        $output = $this->processArray($query);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/RangeQuery.php b/src/Query/RangeQuery.php
index 486009d65e249c8f7b41cf617f5763d72f9cdeca..e96a830c83bf32697f1237654c36f429d405690d 100644
--- a/src/Query/RangeQuery.php
+++ b/src/Query/RangeQuery.php
@@ -11,67 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "range" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class RangeQuery implements BuilderInterface
+class RangeQuery extends \ONGR\ElasticsearchDSL\Query\TermLevel\RangeQuery
 {
-    use ParametersTrait;
-
-    /**
-     * Range control names.
-     */
-    const LT = 'lt';
-    const GT = 'gt';
-    const LTE = 'lte';
-    const GTE = 'gte';
-
-    /**
-     * @var string Field name.
-     */
-    private $field;
-
-    /**
-     * @param string $field
-     * @param array  $parameters
-     */
-    public function __construct($field, array $parameters = [])
-    {
-        $this->setParameters($parameters);
-
-        if ($this->hasParameter(self::GTE) && $this->hasParameter(self::GT)) {
-            unset($this->parameters[self::GT]);
-        }
-
-        if ($this->hasParameter(self::LTE) && $this->hasParameter(self::LT)) {
-            unset($this->parameters[self::LT]);
-        }
-
-        $this->field = $field;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'range';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $output = [
-            $this->field => $this->getParameters(),
-        ];
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/RegexpQuery.php b/src/Query/RegexpQuery.php
index 0752503277df5e53963071cdf74b74117addcaa5..6f6a66968804f0bba5a6f02366d609c8474be8e2 100644
--- a/src/Query/RegexpQuery.php
+++ b/src/Query/RegexpQuery.php
@@ -11,61 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "regexp" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class RegexpQuery implements BuilderInterface
+class RegexpQuery extends \ONGR\ElasticsearchDSL\Query\TermLevel\RegexpQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string Field to be queried.
-     */
-    private $field;
-
-    /**
-     * @var string The actual regexp value to be used.
-     */
-    private $regexpValue;
-
-    /**
-     * @param string $field
-     * @param string $regexpValue
-     * @param array  $parameters
-     */
-    public function __construct($field, $regexpValue, array $parameters = [])
-    {
-        $this->field = $field;
-        $this->regexpValue = $regexpValue;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'regexp';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'value' => $this->regexpValue,
-        ];
-
-        $output = [
-            $this->field => $this->processArray($query),
-        ];
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/ScriptQuery.php b/src/Query/ScriptQuery.php
index 1a1a0c7bed23808ac150a18200835ae3e1595945..42d82f7b1159cad57ca6b23fa2a9b43b1ccf7157 100644
--- a/src/Query/ScriptQuery.php
+++ b/src/Query/ScriptQuery.php
@@ -11,49 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "script" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-script-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class ScriptQuery implements BuilderInterface
+class ScriptQuery extends \ONGR\ElasticsearchDSL\Query\Specialized\ScriptQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string
-     */
-    private $script;
-
-    /**
-     * @param string $script     Script
-     * @param array  $parameters Optional parameters
-     */
-    public function __construct($script, array $parameters = [])
-    {
-        $this->script = $script;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'script';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = ['inline' => $this->script];
-        $output = $this->processArray($query);
-
-        return [$this->getType() => ['script' => $output]];
-    }
 }
diff --git a/src/Query/SimpleQueryStringQuery.php b/src/Query/SimpleQueryStringQuery.php
index a110c5b8ba14cc044b879ed533fb3c5fc486e850..6e529f8ba5a1542fabaace92d2d461da4f65e4c4 100644
--- a/src/Query/SimpleQueryStringQuery.php
+++ b/src/Query/SimpleQueryStringQuery.php
@@ -18,45 +18,9 @@ use ONGR\ElasticsearchDSL\ParametersTrait;
  * Represents Elasticsearch "simple_query_string" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class SimpleQueryStringQuery implements BuilderInterface
+class SimpleQueryStringQuery extends \ONGR\ElasticsearchDSL\Query\FullText\SimpleQueryStringQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string The actual query to be parsed.
-     */
-    private $query;
-
-    /**
-     * @param string $query
-     * @param array  $parameters
-     */
-    public function __construct($query, array $parameters = [])
-    {
-        $this->query = $query;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'simple_query_string';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'query' => $this->query,
-        ];
-
-        $output = $this->processArray($query);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/Specialized/MoreLikeThisQuery.php b/src/Query/Specialized/MoreLikeThisQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..af721ada458a1c0becc83bde34ab22451241760d
--- /dev/null
+++ b/src/Query/Specialized/MoreLikeThisQuery.php
@@ -0,0 +1,64 @@
+<?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\ElasticsearchDSL\Query\Specialized;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "more_like_this" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-mlt-query.html
+ */
+class MoreLikeThisQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string The text to find documents like it, required if ids or docs are not specified.
+     */
+    private $like;
+
+    /**
+     * @param string $like
+     * @param array  $parameters
+     */
+    public function __construct($like, array $parameters = [])
+    {
+        $this->like = $like;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'more_like_this';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [];
+
+        if (($this->hasParameter('ids') === false) || ($this->hasParameter('docs') === false)) {
+            $query['like'] = $this->like;
+        }
+
+        $output = $this->processArray($query);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/Specialized/ScriptQuery.php b/src/Query/Specialized/ScriptQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..07ef289ec5ec0a9ed14f0e35e45974416b5500f9
--- /dev/null
+++ b/src/Query/Specialized/ScriptQuery.php
@@ -0,0 +1,59 @@
+<?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\ElasticsearchDSL\Query\Specialized;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "script" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-script-query.html
+ */
+class ScriptQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string
+     */
+    private $script;
+
+    /**
+     * @param string $script     Script
+     * @param array  $parameters Optional parameters
+     */
+    public function __construct($script, array $parameters = [])
+    {
+        $this->script = $script;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'script';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = ['inline' => $this->script];
+        $output = $this->processArray($query);
+
+        return [$this->getType() => ['script' => $output]];
+    }
+}
diff --git a/src/Query/Specialized/TemplateQuery.php b/src/Query/Specialized/TemplateQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..b8b122df8bcadfea289c825a3e5c983dee6e425e
--- /dev/null
+++ b/src/Query/Specialized/TemplateQuery.php
@@ -0,0 +1,132 @@
+<?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\ElasticsearchDSL\Query\Specialized;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "template" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-template-query.html
+ */
+class TemplateQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string
+     */
+    private $file;
+
+    /**
+     * @var string
+     */
+    private $inline;
+
+    /**
+     * @var array
+     */
+    private $params;
+
+    /**
+     * @param string $file A template of the query
+     * @param string $inline A template of the query
+     * @param array  $params Parameters to insert into template
+     */
+    public function __construct($file = null, $inline = null, array $params = [])
+    {
+        $this->setFile($file);
+        $this->setInline($inline);
+        $this->setParams($params);
+    }
+
+    /**
+     * @return string
+     */
+    public function getFile()
+    {
+        return $this->file;
+    }
+
+    /**
+     * @param string $file
+     */
+    public function setFile($file)
+    {
+        $this->file = $file;
+    }
+
+    /**
+     * @return string
+     */
+    public function getInline()
+    {
+        return $this->inline;
+    }
+
+    /**
+     * @param string $inline
+     */
+    public function setInline($inline)
+    {
+        $this->inline = $inline;
+    }
+
+    /**
+     * @return array
+     */
+    public function getParams()
+    {
+        return $this->params;
+    }
+
+    /**
+     * @param array $params
+     */
+    public function setParams($params)
+    {
+        $this->params = $params;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'template';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $output = array_filter(
+            [
+                'file' => $this->getFile(),
+                'inline' => $this->getInline(),
+                'params' => $this->getParams(),
+            ]
+        );
+
+        if (!isset($output['file']) && !isset($output['inline'])) {
+            throw new \InvalidArgumentException(
+                'Template query requires that either `inline` or `file` parameters are set'
+            );
+        }
+
+        $output = $this->processArray($output);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/TemplateQuery.php b/src/Query/TemplateQuery.php
index 4719ac51255b2684bf2f339d73205cd84db8b64d..d90aae4c6f3d05462ba035264c5d8bb23cb2bfe7 100644
--- a/src/Query/TemplateQuery.php
+++ b/src/Query/TemplateQuery.php
@@ -11,122 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "template" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-template-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class TemplateQuery implements BuilderInterface
+class TemplateQuery extends \ONGR\ElasticsearchDSL\Query\Specialized\TemplateQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string
-     */
-    private $file;
-
-    /**
-     * @var string
-     */
-    private $inline;
-
-    /**
-     * @var array
-     */
-    private $params;
-
-    /**
-     * @param string $file A template of the query
-     * @param string $inline A template of the query
-     * @param array  $params Parameters to insert into template
-     */
-    public function __construct($file = null, $inline = null, array $params = [])
-    {
-        $this->setFile($file);
-        $this->setInline($inline);
-        $this->setParams($params);
-    }
-
-    /**
-     * @return string
-     */
-    public function getFile()
-    {
-        return $this->file;
-    }
-
-    /**
-     * @param string $file
-     */
-    public function setFile($file)
-    {
-        $this->file = $file;
-    }
-
-    /**
-     * @return string
-     */
-    public function getInline()
-    {
-        return $this->inline;
-    }
-
-    /**
-     * @param string $inline
-     */
-    public function setInline($inline)
-    {
-        $this->inline = $inline;
-    }
-
-    /**
-     * @return array
-     */
-    public function getParams()
-    {
-        return $this->params;
-    }
-
-    /**
-     * @param array $params
-     */
-    public function setParams($params)
-    {
-        $this->params = $params;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'template';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $output = array_filter(
-            [
-                'file' => $this->getFile(),
-                'inline' => $this->getInline(),
-                'params' => $this->getParams(),
-            ]
-        );
-
-        if (!isset($output['file']) && !isset($output['inline'])) {
-            throw new \InvalidArgumentException(
-                'Template query requires that either `inline` or `file` parameters are set'
-            );
-        }
-
-        $output = $this->processArray($output);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/TermLevel/ExistsQuery.php b/src/Query/TermLevel/ExistsQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..f72e6e5241a57600087a1ba7223f52eec5a6743a
--- /dev/null
+++ b/src/Query/TermLevel/ExistsQuery.php
@@ -0,0 +1,57 @@
+<?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\ElasticsearchDSL\Query\TermLevel;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+
+/**
+ * Represents Elasticsearch "exists" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-query.html
+ */
+class ExistsQuery implements BuilderInterface
+{
+    /**
+     * @var string
+     */
+    private $field;
+
+    /**
+     * Constructor.
+     *
+     * @param string $field Field value
+     */
+    public function __construct($field)
+    {
+        $this->field = $field;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'exists';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        return [
+            $this->getType() => [
+                'field' => $this->field,
+            ],
+        ];
+    }
+}
diff --git a/src/Query/TermLevel/FuzzyQuery.php b/src/Query/TermLevel/FuzzyQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..e7e7535b550aed591b22ad5f28829cd58aaba9b4
--- /dev/null
+++ b/src/Query/TermLevel/FuzzyQuery.php
@@ -0,0 +1,71 @@
+<?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\ElasticsearchDSL\Query\TermLevel;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "fuzzy" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-fuzzy-query.html
+ */
+class FuzzyQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string
+     */
+    private $field;
+
+    /**
+     * @var string
+     */
+    private $value;
+
+    /**
+     * @param string $field
+     * @param string $value
+     * @param array  $parameters
+     */
+    public function __construct($field, $value, array $parameters = [])
+    {
+        $this->field = $field;
+        $this->value = $value;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'fuzzy';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'value' => $this->value,
+        ];
+
+        $output = [
+            $this->field => $this->processArray($query),
+        ];
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/TermLevel/IdsQuery.php b/src/Query/TermLevel/IdsQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..29edd33d8af83e58e08b9845adb5f9d43f469853
--- /dev/null
+++ b/src/Query/TermLevel/IdsQuery.php
@@ -0,0 +1,62 @@
+<?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\ElasticsearchDSL\Query\TermLevel;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "ids" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-ids-query.html
+ */
+class IdsQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var array
+     */
+    private $values;
+
+    /**
+     * @param array $values
+     * @param array $parameters
+     */
+    public function __construct(array $values, array $parameters = [])
+    {
+        $this->values = $values;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'ids';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'values' => $this->values,
+        ];
+
+        $output = $this->processArray($query);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/TermLevel/PrefixQuery.php b/src/Query/TermLevel/PrefixQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..c453121c490febf3d142be35bfdab579f5d47818
--- /dev/null
+++ b/src/Query/TermLevel/PrefixQuery.php
@@ -0,0 +1,71 @@
+<?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\ElasticsearchDSL\Query\TermLevel;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "prefix" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-query.html
+ */
+class PrefixQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string
+     */
+    protected $field;
+
+    /**
+     * @var string
+     */
+    protected $value;
+
+    /**
+     * @param string $field      Field name.
+     * @param string $value      Value.
+     * @param array  $parameters Optional parameters.
+     */
+    public function __construct($field, $value, array $parameters = [])
+    {
+        $this->field = $field;
+        $this->value = $value;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'prefix';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'value' => $this->value,
+        ];
+
+        $output = [
+            $this->field => $this->processArray($query),
+        ];
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/TermLevel/RangeQuery.php b/src/Query/TermLevel/RangeQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..9a33142dbaec74f344133276803808b6880dff3c
--- /dev/null
+++ b/src/Query/TermLevel/RangeQuery.php
@@ -0,0 +1,77 @@
+<?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\ElasticsearchDSL\Query\TermLevel;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "range" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html
+ */
+class RangeQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * Range control names.
+     */
+    const LT = 'lt';
+    const GT = 'gt';
+    const LTE = 'lte';
+    const GTE = 'gte';
+
+    /**
+     * @var string Field name.
+     */
+    private $field;
+
+    /**
+     * @param string $field
+     * @param array  $parameters
+     */
+    public function __construct($field, array $parameters = [])
+    {
+        $this->setParameters($parameters);
+
+        if ($this->hasParameter(self::GTE) && $this->hasParameter(self::GT)) {
+            unset($this->parameters[self::GT]);
+        }
+
+        if ($this->hasParameter(self::LTE) && $this->hasParameter(self::LT)) {
+            unset($this->parameters[self::LT]);
+        }
+
+        $this->field = $field;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'range';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $output = [
+            $this->field => $this->getParameters(),
+        ];
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/TermLevel/RegexpQuery.php b/src/Query/TermLevel/RegexpQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..4fcee0f78a05ae151547116607f6a27c9e1ece5c
--- /dev/null
+++ b/src/Query/TermLevel/RegexpQuery.php
@@ -0,0 +1,71 @@
+<?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\ElasticsearchDSL\Query\TermLevel;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "regexp" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html
+ */
+class RegexpQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string Field to be queried.
+     */
+    private $field;
+
+    /**
+     * @var string The actual regexp value to be used.
+     */
+    private $regexpValue;
+
+    /**
+     * @param string $field
+     * @param string $regexpValue
+     * @param array  $parameters
+     */
+    public function __construct($field, $regexpValue, array $parameters = [])
+    {
+        $this->field = $field;
+        $this->regexpValue = $regexpValue;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'regexp';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'value' => $this->regexpValue,
+        ];
+
+        $output = [
+            $this->field => $this->processArray($query),
+        ];
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/TermLevel/TermQuery.php b/src/Query/TermLevel/TermQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..fc762a4f9d3ac3200245589f35608b17fe89b6df
--- /dev/null
+++ b/src/Query/TermLevel/TermQuery.php
@@ -0,0 +1,75 @@
+<?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\ElasticsearchDSL\Query\TermLevel;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "term" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html
+ */
+class TermQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string
+     */
+    private $field;
+
+    /**
+     * @var string
+     */
+    private $value;
+
+    /**
+     * @param string $field
+     * @param string $value
+     * @param array  $parameters
+     */
+    public function __construct($field, $value, array $parameters = [])
+    {
+        $this->field = $field;
+        $this->value = $value;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'term';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = $this->processArray();
+
+        if (empty($query)) {
+            $query = $this->value;
+        } else {
+            $query['value'] = $this->value;
+        }
+
+        $output = [
+            $this->field => $query,
+        ];
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/TermLevel/TermsQuery.php b/src/Query/TermLevel/TermsQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..383322346a7aa0903c6fe6272c74b517de282bac
--- /dev/null
+++ b/src/Query/TermLevel/TermsQuery.php
@@ -0,0 +1,71 @@
+<?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\ElasticsearchDSL\Query\TermLevel;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "terms" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html
+ */
+class TermsQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string
+     */
+    private $field;
+
+    /**
+     * @var array
+     */
+    private $terms;
+
+    /**
+     * Constructor.
+     *
+     * @param string $field      Field name
+     * @param array  $terms      An array of terms
+     * @param array  $parameters Optional parameters
+     */
+    public function __construct($field, $terms, array $parameters = [])
+    {
+        $this->field = $field;
+        $this->terms = $terms;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'terms';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            $this->field => $this->terms,
+        ];
+
+        $output = $this->processArray($query);
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/TermLevel/TypeQuery.php b/src/Query/TermLevel/TypeQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..a5ae21c87768b5996b1b9a66317e7f0ce96c3baf
--- /dev/null
+++ b/src/Query/TermLevel/TypeQuery.php
@@ -0,0 +1,57 @@
+<?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\ElasticsearchDSL\Query\TermLevel;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+
+/**
+ * Represents Elasticsearch "type" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-type-query.html
+ */
+class TypeQuery implements BuilderInterface
+{
+    /**
+     * @var string
+     */
+    private $type;
+
+    /**
+     * Constructor.
+     *
+     * @param string $type Type name
+     */
+    public function __construct($type)
+    {
+        $this->type = $type;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'type';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        return [
+            $this->getType() => [
+                'value' => $this->type,
+            ],
+        ];
+    }
+}
diff --git a/src/Query/TermLevel/WildcardQuery.php b/src/Query/TermLevel/WildcardQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..8453c9b271ae6ff45f59309a0b9ad0245bed3ed1
--- /dev/null
+++ b/src/Query/TermLevel/WildcardQuery.php
@@ -0,0 +1,71 @@
+<?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\ElasticsearchDSL\Query\TermLevel;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch "wildcard" query.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html
+ */
+class WildcardQuery implements BuilderInterface
+{
+    use ParametersTrait;
+
+    /**
+     * @var string
+     */
+    private $field;
+
+    /**
+     * @var string
+     */
+    private $value;
+
+    /**
+     * @param string $field
+     * @param string $value
+     * @param array  $parameters
+     */
+    public function __construct($field, $value, array $parameters = [])
+    {
+        $this->field = $field;
+        $this->value = $value;
+        $this->setParameters($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'wildcard';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $query = [
+            'value' => $this->value,
+        ];
+
+        $output = [
+            $this->field => $this->processArray($query),
+        ];
+
+        return [$this->getType() => $output];
+    }
+}
diff --git a/src/Query/TermQuery.php b/src/Query/TermQuery.php
index 783bb6e5fe777c7694397b3e9a9f3cbc4312d6dd..c2751a7adfba6fb36837991aff76b4b8dae37eb2 100644
--- a/src/Query/TermQuery.php
+++ b/src/Query/TermQuery.php
@@ -11,65 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "term" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class TermQuery implements BuilderInterface
+class TermQuery extends \ONGR\ElasticsearchDSL\Query\TermLevel\TermQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string
-     */
-    private $field;
-
-    /**
-     * @var string
-     */
-    private $value;
-
-    /**
-     * @param string $field
-     * @param string $value
-     * @param array  $parameters
-     */
-    public function __construct($field, $value, array $parameters = [])
-    {
-        $this->field = $field;
-        $this->value = $value;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'term';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = $this->processArray();
-
-        if (empty($query)) {
-            $query = $this->value;
-        } else {
-            $query['value'] = $this->value;
-        }
-
-        $output = [
-            $this->field => $query,
-        ];
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/TermsQuery.php b/src/Query/TermsQuery.php
index 647078faff08b075b2e4a0b5cf793166c88cd548..f72d73cc5ce41b234e1beb95988b4d7d0eeb6815 100644
--- a/src/Query/TermsQuery.php
+++ b/src/Query/TermsQuery.php
@@ -11,61 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "terms" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class TermsQuery implements BuilderInterface
+class TermsQuery extends \ONGR\ElasticsearchDSL\Query\TermLevel\TermsQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string
-     */
-    private $field;
-
-    /**
-     * @var array
-     */
-    private $terms;
-
-    /**
-     * Constructor.
-     *
-     * @param string $field      Field name
-     * @param array  $terms      An array of terms
-     * @param array  $parameters Optional parameters
-     */
-    public function __construct($field, $terms, array $parameters = [])
-    {
-        $this->field = $field;
-        $this->terms = $terms;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'terms';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            $this->field => $this->terms,
-        ];
-
-        $output = $this->processArray($query);
-
-        return [$this->getType() => $output];
-    }
 }
diff --git a/src/Query/TypeQuery.php b/src/Query/TypeQuery.php
index 04c62c0bb213edd5cfb28cd54f16ef64109e66cb..aea3d41da4cbf3d46b0dd9ee712a0a5f666a074d 100644
--- a/src/Query/TypeQuery.php
+++ b/src/Query/TypeQuery.php
@@ -11,47 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-
 /**
  * Represents Elasticsearch "type" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-type-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class TypeQuery implements BuilderInterface
+class TypeQuery extends \ONGR\ElasticsearchDSL\Query\TermLevel\TypeQuery
 {
-    /**
-     * @var string
-     */
-    private $type;
-
-    /**
-     * Constructor.
-     *
-     * @param string $type Type name
-     */
-    public function __construct($type)
-    {
-        $this->type = $type;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'type';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        return [
-            $this->getType() => [
-                'value' => $this->type,
-            ],
-        ];
-    }
 }
diff --git a/src/Query/WildcardQuery.php b/src/Query/WildcardQuery.php
index 644776912d80ee9006a5e025236eb91faaddeb69..5383c1c75556356848b71fa877a10caf8d92cdc5 100644
--- a/src/Query/WildcardQuery.php
+++ b/src/Query/WildcardQuery.php
@@ -11,61 +11,13 @@
 
 namespace ONGR\ElasticsearchDSL\Query;
 
-use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\ParametersTrait;
-
 /**
  * Represents Elasticsearch "wildcard" query.
  *
  * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html
+ *
+ * @deprecated Use the extended class instead. This class is left only for BC compatibility.
  */
-class WildcardQuery implements BuilderInterface
+class WildcardQuery extends \ONGR\ElasticsearchDSL\Query\TermLevel\WildcardQuery
 {
-    use ParametersTrait;
-
-    /**
-     * @var string
-     */
-    private $field;
-
-    /**
-     * @var string
-     */
-    private $value;
-
-    /**
-     * @param string $field
-     * @param string $value
-     * @param array  $parameters
-     */
-    public function __construct($field, $value, array $parameters = [])
-    {
-        $this->field = $field;
-        $this->value = $value;
-        $this->setParameters($parameters);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getType()
-    {
-        return 'wildcard';
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function toArray()
-    {
-        $query = [
-            'value' => $this->value,
-        ];
-
-        $output = [
-            $this->field => $this->processArray($query),
-        ];
-
-        return [$this->getType() => $output];
-    }
 }