diff --git a/composer.json b/composer.json
index 5a33e2aba9ec37a5743000d05bec4882dd1e1364..8f2327a054e6aab28d1fdadbc0e0f6d8c5e62f6b 100644
--- a/composer.json
+++ b/composer.json
@@ -11,15 +11,18 @@
         }
     ],
     "require": {
-        "php": ">=7.0",
-        "symfony/serializer": "~3.0|~4.0",
-        "paragonie/random_compat": "^2.0",
-        "elasticsearch/elasticsearch": "~6.0"
+        "php": "^7.0",
+        "symfony/serializer": "^3.0|^4.0",
+        "paragonie/random_compat": "^1.0|^2.0"
     },
     "require-dev": {
-        "phpunit/phpunit": "~6.0",
-        "squizlabs/php_codesniffer": "~3.0",
-        "satooshi/php-coveralls": "~2.0"
+        "elasticsearch/elasticsearch": "^6.0",
+        "phpunit/phpunit": "^6.0",
+        "squizlabs/php_codesniffer": "^3.0",
+        "satooshi/php-coveralls": "~1.0|~2.0"
+    },
+    "suggest": {
+      "elasticsearch/elasticsearch": "This library is for elasticsearch/elasticsearch client to enhance it with DSL functionality."
     },
     "autoload": {
         "psr-4": {
diff --git a/docs/Aggregation/Metric/TopHits.md b/docs/Aggregation/Metric/TopHits.md
index e9e040ca4f2164136de10bf9bf23aedbfe45fa4d..2bd20c8f67eafeb4071eafa34a396f6661d195ff 100644
--- a/docs/Aggregation/Metric/TopHits.md
+++ b/docs/Aggregation/Metric/TopHits.md
@@ -44,9 +44,7 @@ And now the query via DSL:
 
 ```php
 $sort = new FieldSort('last_activity_date', FieldSort::DESC);
-$sorts = new Sorts();
-$sorts->addSort($sort);
-$topHitsAggregation = new TopHitsAggregation('top_tag_hits', 1, null, $sorts);
+$topHitsAggregation = new TopHitsAggregation('top_tag_hits', 1, null, $sort);
 $topHitsAggregation->addParameter('_source', ['include' => ['title']]);
 
 $termsAggregation = new TermsAggregation('top-tags', 'tags');
diff --git a/src/Aggregation/Bucketing/DateRangeAggregation.php b/src/Aggregation/Bucketing/DateRangeAggregation.php
index 9b68dcb4a767a77cb60917217656b5a3d56b941e..d02b3d727084b14abebe2511de0500d5c1e940e8 100644
--- a/src/Aggregation/Bucketing/DateRangeAggregation.php
+++ b/src/Aggregation/Bucketing/DateRangeAggregation.php
@@ -51,7 +51,8 @@ class DateRangeAggregation extends AbstractAggregation
         foreach ($ranges as $range) {
             $from = isset($range['from']) ? $range['from'] : null;
             $to = isset($range['to']) ? $range['to'] : null;
-            $this->addRange($from, $to);
+            $key = isset($range['key']) ? $range['key'] : null;
+            $this->addRange($from, $to, $key);
         }
     }
 
@@ -78,12 +79,13 @@ class DateRangeAggregation extends AbstractAggregation
      *
      * @throws \LogicException
      */
-    public function addRange($from = null, $to = null)
+    public function addRange($from = null, $to = null, $key = null)
     {
         $range = array_filter(
             [
                 'from' => $from,
                 'to' => $to,
+                'key' => $key,
             ]
         );
 
diff --git a/src/Aggregation/Metric/TopHitsAggregation.php b/src/Aggregation/Metric/TopHitsAggregation.php
index 52933ab745c300b4af1c898d9ccbed35da4edc9e..af10e0c1af57db56c3cbfdaa35e07c7a42bbb070 100644
--- a/src/Aggregation/Metric/TopHitsAggregation.php
+++ b/src/Aggregation/Metric/TopHitsAggregation.php
@@ -35,9 +35,9 @@ class TopHitsAggregation extends AbstractAggregation
     private $from;
 
     /**
-     * @var BuilderInterface How the top matching hits should be sorted.
+     * @var BuilderInterface[] How the top matching hits should be sorted.
      */
-    private $sort;
+    private $sorts = [];
 
     /**
      * Constructor for top hits.
@@ -52,7 +52,7 @@ class TopHitsAggregation extends AbstractAggregation
         parent::__construct($name);
         $this->setFrom($from);
         $this->setSize($size);
-        $this->setSort($sort);
+        $this->addSort($sort);
     }
 
     /**
@@ -76,23 +76,29 @@ class TopHitsAggregation extends AbstractAggregation
     }
 
     /**
-     * Return sort.
-     *
-     * @return BuilderInterface
+     * @return BuilderInterface[]
      */
-    public function getSort()
+    public function getSorts()
     {
-        return $this->sort;
+        return $this->sorts;
     }
 
     /**
-     * Set sort.
+     * @param BuilderInterface[] $sorts
+     */
+    public function setSorts(array $sorts)
+    {
+        $this->sorts = $sorts;
+    }
+
+    /**
+     * Add sort.
      *
      * @param BuilderInterface $sort
      */
-    public function setSort($sort)
+    public function addSort($sort)
     {
-        $this->sort = $sort;
+        $this->sorts[] = $sort;
     }
 
     /**
@@ -128,9 +134,19 @@ class TopHitsAggregation extends AbstractAggregation
      */
     public function getArray()
     {
+        $sortsOutput = [];
+        $addedSorts = array_filter($this->getSorts());
+        if ($addedSorts) {
+            foreach ($addedSorts as $sort) {
+                $sortsOutput[] = $sort->toArray();
+            }
+        } else {
+            $sortsOutput = null;
+        }
+
         $output = array_filter(
             [
-                'sort' => $this->getSort() ? $this->getSort()->toArray() : null,
+                'sort' => $sortsOutput,
                 'size' => $this->getSize(),
                 'from' => $this->getFrom(),
             ],
@@ -141,4 +157,31 @@ class TopHitsAggregation extends AbstractAggregation
 
         return empty($output) ? new \stdClass() : $output;
     }
+
+    /**
+     * @deprecated sorts now is a container, use `getSorts()`instead.
+     * Return sort.
+     *
+     * @return BuilderInterface
+     */
+    public function getSort()
+    {
+        if (isset($this->sorts[0])) {
+            return $this->sorts[0];
+        }
+
+        return null;
+    }
+
+    /**
+     * @deprecated sorts now is a container, use `addSort()`instead.
+     *
+     * Set sort.
+     *
+     * @param BuilderInterface $sort
+     */
+    public function setSort(BuilderInterface $sort)
+    {
+        $this->sort = $sort;
+    }
 }
diff --git a/src/Query/Geo/GeoShapeQuery.php b/src/Query/Geo/GeoShapeQuery.php
index 9e51537a4f0404cb3df287eb269ada244646a0da..584f335acb16d922685b433b40bd067545538487 100644
--- a/src/Query/Geo/GeoShapeQuery.php
+++ b/src/Query/Geo/GeoShapeQuery.php
@@ -23,6 +23,11 @@ class GeoShapeQuery implements BuilderInterface
 {
     use ParametersTrait;
 
+    const INTERSECTS = 'intersects';
+    const DISJOINT = 'disjoint';
+    const WITHIN = 'within';
+    const CONTAINS = 'contains';
+
     /**
      * @var array
      */
@@ -50,10 +55,18 @@ class GeoShapeQuery implements BuilderInterface
      * @param string $field       Field name.
      * @param string $type        Shape type.
      * @param array  $coordinates Shape coordinates.
+     * @param string $relation    Spatial relation.
      * @param array  $parameters  Additional parameters.
      */
-    public function addShape($field, $type, array $coordinates, array $parameters = [])
+    public function addShape($field, $type, array $coordinates, $relation = self::INTERSECTS, array $parameters = [])
     {
+        // TODO: remove this in the next major version
+        if (is_array($relation)) {
+            $parameters = $relation;
+            $relation = self::INTERSECTS;
+            trigger_error('$parameters as parameter 4 in addShape is deprecated', E_USER_DEPRECATED);
+        }
+
         $filter = array_merge(
             $parameters,
             [
@@ -62,7 +75,10 @@ class GeoShapeQuery implements BuilderInterface
             ]
         );
 
-        $this->fields[$field]['shape'] = $filter;
+        $this->fields[$field] = [
+            'shape' => $filter,
+            'relation' => $relation,
+        ];
     }
 
     /**
diff --git a/tests/Unit/Aggregation/Metric/TopHitsAggregationTest.php b/tests/Unit/Aggregation/Metric/TopHitsAggregationTest.php
index 046390a0221e391de66e010fe9d5a1919d96055c..f6018dc819d5f4f0f0dfa15b04ca678a4b875402 100644
--- a/tests/Unit/Aggregation/Metric/TopHitsAggregationTest.php
+++ b/tests/Unit/Aggregation/Metric/TopHitsAggregationTest.php
@@ -30,7 +30,7 @@ class TopHitsAggregationTest extends \PHPUnit\Framework\TestCase
         $expected = [
             'top_hits' => [
                 'sort' => [
-                    'acme' => ['order' => 'asc'],
+                    ['acme' => ['order' => 'asc']],
                 ],
                 'size' => 1,
                 'from' => 1,
diff --git a/tests/Unit/Query/Geo/GeoShapeQueryTest.php b/tests/Unit/Query/Geo/GeoShapeQueryTest.php
index a0135bf78192b75a62f81449c74ff687e6ac1ec5..4a7a43273d6fc3d0c92b162de6639503f51b39e8 100644
--- a/tests/Unit/Query/Geo/GeoShapeQueryTest.php
+++ b/tests/Unit/Query/Geo/GeoShapeQueryTest.php
@@ -21,7 +21,7 @@ class GeoShapeQueryTest extends \PHPUnit\Framework\TestCase
     public function testToArray()
     {
         $filter = new GeoShapeQuery(['param1' => 'value1']);
-        $filter->addShape('location', 'envelope', [[13, 53], [14, 52]]);
+        $filter->addShape('location', 'envelope', [[13, 53], [14, 52]], GeoShapeQuery::INTERSECTS);
 
         $expected = [
             'geo_shape' => [
@@ -30,6 +30,7 @@ class GeoShapeQueryTest extends \PHPUnit\Framework\TestCase
                         'type' => 'envelope',
                         'coordinates' => [[13, 53], [14, 52]],
                     ],
+                    'relation' => 'intersects'
                 ],
                 'param1' => 'value1',
             ],