diff --git a/docs/Aggregation/Avg.md b/docs/Aggregation/Avg.md
new file mode 100644
index 0000000000000000000000000000000000000000..c72b519d98fb1da42cf1b9d9cb103e7966cd10c3
--- /dev/null
+++ b/docs/Aggregation/Avg.md
@@ -0,0 +1,34 @@
+# Avg Aggregation
+
+> More info about avg aggregation is in the [official elasticsearch docs][1]
+
+A single-value metrics aggregation that computes the average of numeric values that are extracted from the aggregated documents.
+
+
+## Simple example
+
+```JSON
+{
+    "aggregations": {
+        "agg_avg_grade": {
+            "avg": {
+                "field": "grade"
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$avgAggregation = new AvgAggregation('avg_grade');
+$avgAggregation->setField('grade');
+
+$search = new Search();
+$search->addAggregation($avgAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-avg-aggregation.html
\ No newline at end of file
diff --git a/docs/Aggregation/Cardinality.md b/docs/Aggregation/Cardinality.md
new file mode 100644
index 0000000000000000000000000000000000000000..642869f4097376fbc11ea09e85d6c5802f326b94
--- /dev/null
+++ b/docs/Aggregation/Cardinality.md
@@ -0,0 +1,32 @@
+# Cardinality Aggregation
+
+> More info about cardinality aggregation is in the [official elasticsearch docs][1]
+
+A single-value metrics aggregation that calculates an approximate count of distinct values.
+
+## Simple example
+
+```JSON
+{
+     "aggregations" : {
+         "agg_author_count" : {
+             "cardinality" : {
+                 "field" : "author"
+             }
+         }
+     }
+ }
+```
+
+And now the query via DSL:
+
+```php
+$cardinalityAggregation = new CardinalityAggregation('author_count', 'author');
+
+$search = new Search();
+$search->addAggregation($cardinalityAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-cardinality-aggregation.html
diff --git a/docs/Aggregation/Children.md b/docs/Aggregation/Children.md
new file mode 100644
index 0000000000000000000000000000000000000000..4358561d4ca8569a78e081c4bd0ce9e127ca8513
--- /dev/null
+++ b/docs/Aggregation/Children.md
@@ -0,0 +1,43 @@
+# Children Aggregation
+
+> More info about children aggregation is in the [official elasticsearch docs][1]
+
+A special single bucket aggregation that enables aggregating from buckets on parent
+document types to buckets on child documents.
+
+## Simple example
+
+```JSON
+{
+    "aggregations": {
+        "agg_author_count": {
+            "children": {
+                "type": "answer"
+            },
+            "aggregations": {
+                "agg_top_names": {
+                    "terms": {
+                        "field": "owner.display_name"
+                    }
+                }
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termsAggregation = new TermsAggregation('top_names', 'owner.display_name');
+
+$childrenAggregation = new ChildrenAggregation('author_count', 'answer');
+$childrenAggregation->addAggregation($termsAggregation);
+
+$search = new Search();
+$search->addAggregation($childrenAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-children-aggregation.html
diff --git a/docs/Aggregation/DateRange.md b/docs/Aggregation/DateRange.md
new file mode 100644
index 0000000000000000000000000000000000000000..c1f48a0e37af4b9b4bb12497e1836f80a57ffb1a
--- /dev/null
+++ b/docs/Aggregation/DateRange.md
@@ -0,0 +1,53 @@
+# Date Range Aggregation
+
+> More info about date range aggregation is in the [official elasticsearch docs][1]
+
+A range aggregation that is dedicated for date values.
+
+## Simple example
+
+```JSON
+{
+    "aggregations": {
+        "agg_range": {
+            "date_range": {
+                "field": "date",
+                "format": "MM-yyy",
+                "ranges": [
+                    { "to": "now-10M/M" }, 
+                    { "from": "now-10M/M" } 
+                ]
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$dateRangeAggregation = new DateRangeAggregation('range');
+$dateRangeAggregation->setField('date');
+$dateRangeAggregation->setFormat('MM-yyy');
+$dateRangeAggregation->addRange(null, 'now-10M/M');
+$dateRangeAggregation->addRange('now-10M/M', null);
+```
+
+Or : 
+
+```php
+$dateRangeAggregation = new DateRangeAggregation(
+    'range',
+    'date',
+    'MM-yyy',
+    [
+        ['to' => 'now-10M/M'],
+        ['from' => 'now-10M/M'],
+    ]
+);
+
+$search = new Search();
+$search->addAggregation($dateRangeAggregation);
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-daterange-aggregation.html
diff --git a/docs/Aggregation/ExtendedStats.md b/docs/Aggregation/ExtendedStats.md
new file mode 100644
index 0000000000000000000000000000000000000000..69225844bc342d5048d83690e1bf960dfbcad355
--- /dev/null
+++ b/docs/Aggregation/ExtendedStats.md
@@ -0,0 +1,30 @@
+# Extended Stats Aggregation
+
+> More info about extended stats aggregation is in the [official elasticsearch docs][1]
+
+A multi-value metrics aggregation that computes stats over numeric values extracted from the aggregated documents.
+
+## Simple example
+
+```JSON
+{
+    "aggregations" : {
+        "agg_grades_stats" : {
+            "extended_stats" : { "field" : "grade" }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$extendedStatsAggregation = new ExtendedStatsAggregation('grades_stats', 'grade');
+
+$search = new Search();
+$search->addAggregation($extendedStatsAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-extendedstats-aggregation.html
diff --git a/docs/Aggregation/Filter.md b/docs/Aggregation/Filter.md
new file mode 100644
index 0000000000000000000000000000000000000000..9a7a4d21b62f37a1aefa1f3f62817d5dc0fd245f
--- /dev/null
+++ b/docs/Aggregation/Filter.md
@@ -0,0 +1,39 @@
+# Filter Aggregation
+
+> More info about filter aggregation is in the [official elasticsearch docs][1]
+
+Defines a single bucket of all the documents in the current document set context that
+match a specified filter. Often this will be used to narrow down the current aggregation
+context to a specific set of documents.
+
+## Simple example
+
+```JSON
+{
+    "aggregations" : {
+        "agg_red_products" : {
+            "filter" : { "term": { "color": "red" } },
+            "aggs" : {
+                "agg_avg_price" : { "avg" : { "field" : "price" } }
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termFilter = new TermFilter('color', 'red');
+$avgAggregation = new AvgAggregation('avg_price', 'price');
+
+$filterAggregation = new FilterAggregation('grades_stats', $termFilter);
+$filterAggregation->addAggregation($avgAggregation);
+
+$search = new Search();
+$search->addAggregation($filterAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filter-aggregation.html
diff --git a/docs/Aggregation/Filters.md b/docs/Aggregation/Filters.md
new file mode 100644
index 0000000000000000000000000000000000000000..8ec4451144eccebeaf46f0748e4aa6dad10c14a1
--- /dev/null
+++ b/docs/Aggregation/Filters.md
@@ -0,0 +1,86 @@
+# Filters Aggregation
+
+> More info about filters aggregation is in the [official elasticsearch docs][1]
+
+Defines a multi bucket aggregations where each bucket is associated with a filter.
+Each bucket will collect all documents that match its associated filter.
+
+Filters can have names or be anonymous, this is controlled by setAnonymous method.
+By default filters are not anonymous and trying to add filter without name will result
+in exception.
+
+## Named example
+
+```JSON
+{
+  "aggregations" : {
+    "agg_messages" : {
+      "filters" : {
+        "filters" : {
+          "errors" :   { "term" : { "body" : "error"   }},
+          "warnings" : { "term" : { "body" : "warning" }}
+        }
+      },
+      "aggregations" : {
+        "agg_monthly" : {
+          "histogram" : {
+            "field" : "timestamp",
+            "interval" : "1M"
+          }
+        }
+      }
+    }
+  }
+}
+```
+
+And now the query via DSL:
+
+```php
+$errorTermFilter = new TermFilter('body', 'error');
+$warningTermFilter = new TermFilter('body', 'warning');
+
+$histogramAggregation = new HistogramAggregation('monthly', 'timestamp');
+$histogramAggregation->setInterval('1M');
+
+$filterAggregation = new FiltersAggregation(
+    'grades_stats',
+    [
+        'error' => $errorTermFilter,
+        'warning' => $warningTermFilter,
+    ]
+);
+$filterAggregation->addAggregation($histogramAggregation);
+
+$search = new Search();
+$search->addAggregation($filterAggregation);
+
+$queryArray = $search->toArray();
+```
+
+## Anonymous example
+
+```php
+$errorTermFilter = new TermFilter('body', 'error');
+$warningTermFilter = new TermFilter('body', 'warning');
+
+$histogramAggregation = new HistogramAggregation('monthly', 'timestamp');
+$histogramAggregation->setInterval('1M');
+
+$filterAggregation = new FiltersAggregation(
+    'grades_stats',
+    [
+        $errorTermFilter,
+        $warningTermFilter,
+    ],
+    true
+);
+$filterAggregation->addAggregation($histogramAggregation);
+
+$search = new Search();
+$search->addAggregation($filterAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filters-aggregation.html
\ No newline at end of file
diff --git a/docs/Aggregation/GeoBounds.md b/docs/Aggregation/GeoBounds.md
new file mode 100644
index 0000000000000000000000000000000000000000..0e75e1056a9005d90e683814e47901f44a5265b5
--- /dev/null
+++ b/docs/Aggregation/GeoBounds.md
@@ -0,0 +1,33 @@
+# Geo Bounds Aggregation
+
+> More info about geo bounds aggregation is in the [official elasticsearch docs][1]
+
+A metric aggregation that computes the bounding box containing all geo_point values for a field.
+
+## Simple example
+
+```JSON
+{
+    "aggregations" : {
+        "agg_viewport" : {
+            "geo_bounds" : {
+                "field" : "location",
+                "wrap_longitude" : true
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$geoBoundsAggregation = new GeoBoundsAggregation('viewport', 'location');
+
+$search = new Search();
+$search->addAggregation($geoBoundsAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-geobounds-aggregation.html
diff --git a/docs/Aggregation/GeoDistance.md b/docs/Aggregation/GeoDistance.md
new file mode 100644
index 0000000000000000000000000000000000000000..5f4eea5685a0c1fa061d829882c2eb4c8852a5db
--- /dev/null
+++ b/docs/Aggregation/GeoDistance.md
@@ -0,0 +1,48 @@
+# Geo Distance Aggregation
+
+> More info about geo distance aggregation is in the [official elasticsearch docs][1]
+
+A multi-bucket aggregation that works on geo_point fields
+and conceptually works very similar to the range aggregation.
+
+## Simple example
+
+```JSON
+{
+    "aggregations" : {
+        "rings_around_amsterdam" : {
+            "geo_distance" : {
+                "field" : "location",
+                "origin" : "52.3760, 4.894",
+                "ranges" : [
+                    { "to" : 100 },
+                    { "from" : 100, "to" : 300 },
+                    { "from" : 300 }
+                ]
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$geoDistanceAggregation = new GeoDistanceAggregation(
+    'rings_around_amsterdam',
+    'location',
+    '52.3760, 4.894',
+    [
+        ['to' => 100],
+        ['from' => 100, 'to' => 300],
+        ['from' => 300],
+    ]
+);
+
+$search = new Search();
+$search->addAggregation($geoDistanceAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-geodistance-aggregation.html
diff --git a/docs/Aggregation/GeoHashGrid.md b/docs/Aggregation/GeoHashGrid.md
new file mode 100644
index 0000000000000000000000000000000000000000..e372264601bfe2ebb7243a4fb3117fb574ab0a63
--- /dev/null
+++ b/docs/Aggregation/GeoHashGrid.md
@@ -0,0 +1,38 @@
+# Geo Hash Grid Aggregation
+
+> More info about geo hash grid aggregation is in the [official elasticsearch docs][1]
+
+A multi-bucket aggregation that works on geo_point fields and groups points into buckets
+that represent cells in a grid.
+
+## Simple example
+
+```JSON
+{
+    "aggregations" : {
+        "agg_GrainGeoHashGrid" : {
+            "geohash_grid" : {
+                "field" : "location",
+                "precision" : 3
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$geoHashGridAggregation = new GeoHashGridAggregation(
+    'GrainGeoHashGrid',
+    'location',
+    3
+);
+
+$search = new Search();
+$search->addAggregation($geoHashGridAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-geohashgrid-aggregation.html
diff --git a/docs/Aggregation/Global.md b/docs/Aggregation/Global.md
new file mode 100644
index 0000000000000000000000000000000000000000..fcb7821cfe92afac4ceec8e8844053321109b17f
--- /dev/null
+++ b/docs/Aggregation/Global.md
@@ -0,0 +1,41 @@
+# Global Aggregation
+
+> More info about cardinality aggregation is in the [official elasticsearch docs][1]
+
+Defines a single bucket of all the documents within the search execution
+context. This context is defined by the indices and the document types
+you’re searching on, but is **not influenced** by the search query itself.
+
+## Simple example
+
+```JSON
+{
+    "aggregations": {
+        "agg_all_products": {
+            "global": {},
+            "aggregations": {
+                "agg_avg_price": {
+                    "avg": {
+                        "field": "price"
+                    }
+                }
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$avgAggregation = new AvgAggregation('avg_price', 'price');
+$globalAggregation = new GlobalAggregation('all_products');
+$globalAggregation->addAggregation($avgAggregation);
+
+$search = new Search();
+$search->addAggregation($globalAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-global-aggregation.html
diff --git a/docs/Aggregation/Histogram.md b/docs/Aggregation/Histogram.md
new file mode 100644
index 0000000000000000000000000000000000000000..be18516a4f0ae96ca0245180c2989d9fc79d8104
--- /dev/null
+++ b/docs/Aggregation/Histogram.md
@@ -0,0 +1,34 @@
+# Histogram Aggregation
+
+> More info about histogram aggregation is in the [official elasticsearch docs][1]
+
+A multi-bucket values source based aggregation that can be applied on numeric values extracted from
+the documents. It dynamically builds fixed size (a.k.a. interval) buckets over the values.
+
+## Simple example
+
+```JSON
+{
+    "aggregations": {
+        "agg_prices": {
+            "histogram": {
+                "field": "price",
+                "interval": 50
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$histogramAggregation = new HistogramAggregation('prices', 'price', 50);
+
+$search = new Search();
+$search->addAggregation($histogramAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-histogram-aggregation.html
diff --git a/docs/Aggregation/Ipv4Range.md b/docs/Aggregation/Ipv4Range.md
new file mode 100644
index 0000000000000000000000000000000000000000..215d91c7e5189e1d9cfbd0b942ba2c7ded4e9e0b
--- /dev/null
+++ b/docs/Aggregation/Ipv4Range.md
@@ -0,0 +1,74 @@
+# Ipv4 Range Aggregation
+
+> More info about ipv4 range aggregation is in the [official elasticsearch docs][1]
+
+Just like the dedicated date range aggregation, there is also a dedicated
+range aggregation for IPv4 typed fields.
+
+## Simple example
+
+```JSON
+{
+    "aggregations" : {
+        "agg_ip_range" : {
+            "ip_range" : {
+                "field" : "ip",
+                "ranges" : [
+                    { "to" : "10.0.0.5" },
+                    { "from" : "10.0.0.5" }
+                ]
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$ipv4RangeAggregation = new Ipv4RangeAggregation(
+    'ip_range',
+    'ip',
+    [
+        ['to' => '10.0.0.5'],
+        ['from' => '10.0.0.5'],
+    ]
+);
+
+$search = new Search();
+$search->addAggregation($ipv4RangeAggregation);
+
+$queryArray = $search->toArray();
+```
+
+## Example using masks
+
+```php
+$ipv4RangeAggregation = new Ipv4RangeAggregation(
+    'ip_range',
+    'ip',
+    ['10.0.0.0/25']
+);
+
+$search = new Search();
+$search->addAggregation($ipv4RangeAggregation);
+
+$queryArray = $search->toArray();
+```
+
+## Example using adders
+
+```php
+$ipv4RangeAggregation = new Ipv4RangeAggregation('ip_range', 'ip');
+$ipv4RangeAggregation->addMask('10.0.0.0/25');
+$ipv4RangeAggregation->addRange(null, '10.0.0.5');
+$ipv4RangeAggregation->addRange('10.0.0.5');
+$ipv4RangeAggregation->addRange('10.0.0.0', '10.0.0.127');
+
+$search = new Search();
+$search->addAggregation($ipv4RangeAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-iprange-aggregation.html
diff --git a/docs/Aggregation/Max.md b/docs/Aggregation/Max.md
new file mode 100644
index 0000000000000000000000000000000000000000..fff8bd350daa47ece47989b0c2512d7ca583f988
--- /dev/null
+++ b/docs/Aggregation/Max.md
@@ -0,0 +1,29 @@
+# Max Aggregation
+
+> More info about max aggregation is in the [official elasticsearch docs][1]
+
+A single-value metrics aggregation that keeps track and returns the
+maximum value among the numeric values extracted from the aggregated documents.
+
+## Simple example
+
+```JSON
+{
+    "aggregations" : {
+        "max_price" : { "max" : { "field" : "price" } }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$maxAggregation = new MaxAggregation('max_price', 'price');
+
+$search = new Search();
+$search->addAggregation($maxAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-max-aggregation.html
diff --git a/docs/Aggregation/Min.md b/docs/Aggregation/Min.md
new file mode 100644
index 0000000000000000000000000000000000000000..e1ac233e77881e477ce1830394eb8c091a0813dc
--- /dev/null
+++ b/docs/Aggregation/Min.md
@@ -0,0 +1,29 @@
+# Min Aggregation
+
+> More info about min aggregation is in the [official elasticsearch docs][1]
+
+A single-value metrics aggregation that keeps track and returns the minimum value among
+numeric values extracted from the aggregated documents.
+
+## Simple example
+
+```JSON
+{
+    "aggregations" : {
+        "min_price" : { "min" : { "field" : "price" } }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$minAggregation = new MinAggregation('min_price', 'price');
+
+$search = new Search();
+$search->addAggregation($minAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-min-aggregation.html
diff --git a/docs/Aggregation/Missing.md b/docs/Aggregation/Missing.md
new file mode 100644
index 0000000000000000000000000000000000000000..1f3cdd302ef601c272588f075a092d9eb6c8b2e1
--- /dev/null
+++ b/docs/Aggregation/Missing.md
@@ -0,0 +1,31 @@
+# Missing Aggregation
+
+> More info about missing aggregation is in the [official elasticsearch docs][1]
+
+A field data based single bucket aggregation, that creates a bucket of all documents
+in the current document set context that are missing a field value.
+
+## Simple example
+
+```JSON
+{
+     "aggregations" : {
+         "agg_products_without_a_price" : {
+             "missing" : { "field" : "price" }
+         }
+     }
+ }
+```
+
+And now the query via DSL:
+
+```php
+$missingAggregation = new MissingAggregation('products_without_a_price', 'price');
+
+$search = new Search();
+$search->addAggregation($missingAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-missing-aggregation.html
diff --git a/docs/Aggregation/Nested.md b/docs/Aggregation/Nested.md
new file mode 100644
index 0000000000000000000000000000000000000000..f7cf99c25f922eca4dd58a4ba47c9f3f3f2aec1e
--- /dev/null
+++ b/docs/Aggregation/Nested.md
@@ -0,0 +1,37 @@
+# Nested Aggregation
+
+> More info about nested aggregation is in the [official elasticsearch docs][1]
+
+A special single bucket aggregation that enables aggregating nested documents.
+
+## Simple example
+
+```JSON
+{
+    "aggregations" : {
+        "agg_resellers" : {
+            "nested" : {
+                "path" : "resellers"
+            },
+            "aggregations" : {
+                "agg_min_price" : { "min" : { "field" : "resellers.price" } }
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$minAggregation = new MinAggregation('min_price', 'resellers.price');
+$nestedAggregation = new NestedAggregation('resellers', 'resellers');
+$nestedAggregation->addAggregation($minAggregation);
+
+$search = new Search();
+$search->addAggregation($nestedAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-nested-aggregation.html
diff --git a/docs/Aggregation/PercentileRanks.md b/docs/Aggregation/PercentileRanks.md
new file mode 100644
index 0000000000000000000000000000000000000000..52f3826f01418646a43a77a60edc06113c499feb
--- /dev/null
+++ b/docs/Aggregation/PercentileRanks.md
@@ -0,0 +1,34 @@
+# Percentile Ranks Aggregation
+
+> More info about percentile ranks aggregation is in the [official elasticsearch docs][1]
+
+A multi-value metrics aggregation that calculates one or more percentile
+ranks over numeric values extracted from the aggregated documents.
+
+## Simple example
+
+```JSON
+{
+    "aggregations" : {
+        "agg_load_time_outlier" : {
+            "percentile_ranks" : {
+                "field" : "load_time",
+                "values" : [15, 30]
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$percentileRanksAggregation = new PercentileRanksAggregation('load_time_outlier', 'load_time', [15, 30]);
+
+$search = new Search();
+$search->addAggregation($percentileRanksAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-percentile-rank-aggregation.html
diff --git a/docs/Aggregation/Percentiles.md b/docs/Aggregation/Percentiles.md
new file mode 100644
index 0000000000000000000000000000000000000000..c4c4481c8607e8528f30f103416d4900a85e2dac
--- /dev/null
+++ b/docs/Aggregation/Percentiles.md
@@ -0,0 +1,33 @@
+# Percentiles Aggregation
+
+> More info about percentiles aggregation is in the [official elasticsearch docs][1]
+
+A multi-value metrics aggregation that calculates one or more percentiles over
+numeric values extracted from the aggregated documents.
+
+## Simple example
+
+```JSON
+{
+    "aggregations" : {
+        "agg_load_time_outlier" : {
+            "percentiles" : {
+                "field" : "load_time"
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$percentilesAggregation = new PercentilesAggregation('load_time_outlier', 'load_time');
+
+$search = new Search();
+$search->addAggregation($percentilesAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-cardinality-aggregation.html
diff --git a/docs/Aggregation/Range.md b/docs/Aggregation/Range.md
new file mode 100644
index 0000000000000000000000000000000000000000..45b9facf572ee2aa7784db345b41d94e85ece156
--- /dev/null
+++ b/docs/Aggregation/Range.md
@@ -0,0 +1,82 @@
+# Range Aggregation
+
+> More info about range aggregation is in the [official elasticsearch docs][1]
+
+A multi-bucket value source based aggregation that enables the user to define a set of
+ranges - each representing a bucket.
+
+## Simple example
+
+```JSON
+{
+    "aggs" : {
+        "agg_price_ranges" : {
+            "range" : {
+                "field" : "price",
+                "ranges" : [
+                    { "to" : 50 },
+                    { "from" : 50, "to" : 100 },
+                    { "from" : 100 }
+                ]
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$rangeAggregation = new RangeAggregation(
+    'price_ranges',
+    'price',
+    [
+        ['to' => 50],
+        ['from' => 50, 'to' => 100],
+        ['from' => 100],
+    ]
+);
+
+$search = new Search();
+$search->addAggregation($rangeAggregation);
+
+$queryArray = $search->toArray();
+```
+
+## Keyed example
+
+```php
+$rangeAggregation = new RangeAggregation(
+    'price_ranges',
+    'price',
+    [
+        ['key' => 'cheap', 'to' => 50],
+        ['from' => 50, 'to' => 100],
+        ['key' => 'expensive', 'from' => 100],
+    ],
+    true
+);
+
+$search = new Search();
+$search->addAggregation($rangeAggregation);
+
+$queryArray = $search->toArray();
+```
+
+## Adder example
+
+```php
+$rangeAggregation = new RangeAggregation('price_ranges', 'price');
+$rangeAggregation->setKeyed(true);
+$rangeAggregation->addRange(null, 50, 'cheap');
+$rangeAggregation->addRange(50, 100);
+$rangeAggregation->addRange(100, null, 'expensive');
+
+$search = new Search();
+$search->addAggregation($rangeAggregation);
+
+$queryArray = $search->toArray();
+```
+
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-range-aggregation.html
diff --git a/docs/Aggregation/ReverseNested.md b/docs/Aggregation/ReverseNested.md
new file mode 100644
index 0000000000000000000000000000000000000000..7ef138aa86cc3cec6e422d1482d3b6e679af819a
--- /dev/null
+++ b/docs/Aggregation/ReverseNested.md
@@ -0,0 +1,60 @@
+# Reverse Nested Aggregation
+
+> More info about reverse nested aggregation is in the [official elasticsearch docs][1]
+
+A special single bucket aggregation that enables aggregating on parent docs from nested documents.
+
+## Simple example
+
+```JSON
+{
+  "aggregations": {
+    "agg_comments": {
+      "nested": {
+        "path": "comments"
+      },
+      "aggregations": {
+        "agg_top_usernames": {
+          "terms": {
+            "field": "comments.username"
+          },
+          "aggregations": {
+            "agg_comment_to_issue": {
+              "reverse_nested": {},
+              "aggregations": {
+                "top_tags_per_comment": {
+                  "terms": {
+                    "field": "tags"
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+```
+
+And now the query via DSL:
+
+```php
+$tagsTermsAggregations = new TermsAggregation('top_tags_per_comment', 'tags');
+
+$reverseNestedAggregation = new ReverseNestedAggregation('comment_to_issue');
+$reverseNestedAggregation->addAggregation($tagsTermsAggregations);
+
+$usernameTermsAggregation = new TermsAggregation('top_usernames', 'comments.username');
+$usernameTermsAggregation->addAggregation($reverseNestedAggregation);
+
+$nestedAggregation = new NestedAggregation('comments', 'comments');
+$nestedAggregation->addAggregation($usernameTermsAggregation);
+
+$search = new Search();
+$search->addAggregation($nestedAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-reverse-nested-aggregation.html
diff --git a/docs/Aggregation/Stats.md b/docs/Aggregation/Stats.md
new file mode 100644
index 0000000000000000000000000000000000000000..e4ca438410eb103fef5dcdf473112b2c7b1a7dbe
--- /dev/null
+++ b/docs/Aggregation/Stats.md
@@ -0,0 +1,29 @@
+# Stats Aggregation
+
+> More info about stats aggregation is in the [official elasticsearch docs][1]
+
+A multi-value metrics aggregation that computes stats over numeric
+values extracted from the aggregated documents.
+
+## Simple example
+
+```JSON
+{
+    "aggregations" : {
+        "agg_grades_stats" : { "stats" : { "field" : "grade" } }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$statsAggregation = new StatsAggregation('grades_stats', 'grade');
+
+$search = new Search();
+$search->addAggregation($statsAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-stats-aggregation.html
diff --git a/docs/Aggregation/Sum.md b/docs/Aggregation/Sum.md
new file mode 100644
index 0000000000000000000000000000000000000000..bc5929ac093dfd2f287d0d1f7e34f84a641f335a
--- /dev/null
+++ b/docs/Aggregation/Sum.md
@@ -0,0 +1,28 @@
+# Sum Aggregation
+
+> More info about sum aggregation is in the [official elasticsearch docs][1]
+
+A single-value metrics aggregation that sums up numeric values that are extracted from the aggregated documents.
+
+## Simple example
+
+```JSON
+{
+    "aggregations" : {
+        "agg_intraday_return" : { "sum" : { "field" : "change" } }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$sumAggregation = new SumAggregation('intraday_return', 'change');
+
+$search = new Search();
+$search->addAggregation($sumAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-sum-aggregation.html
diff --git a/docs/Aggregation/Terms.md b/docs/Aggregation/Terms.md
new file mode 100644
index 0000000000000000000000000000000000000000..66a8213c01d838b6b787d7850f99a9099bd5b4e6
--- /dev/null
+++ b/docs/Aggregation/Terms.md
@@ -0,0 +1,31 @@
+# Terms Aggregation
+
+> More info about terms aggregation is in the [official elasticsearch docs][1]
+
+A multi-bucket value source based aggregation where buckets are dynamically
+built - one per unique value.
+
+## Simple example
+
+```JSON
+{
+    "aggregations" : {
+        "agg_genders" : {
+            "terms" : { "field" : "gender" }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termsAggregation = new TermsAggregation('genders', 'gender');
+
+$search = new Search();
+$search->addAggregation($termsAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html
diff --git a/docs/Aggregation/TopHits.md b/docs/Aggregation/TopHits.md
new file mode 100644
index 0000000000000000000000000000000000000000..33ba81ea357109dd0d271f4ad8de6d06c70973e7
--- /dev/null
+++ b/docs/Aggregation/TopHits.md
@@ -0,0 +1,62 @@
+# Top Hits Aggregation
+
+> More info about top hits aggregation is in the [official elasticsearch docs][1]
+
+A top hits metric aggregator keeps track of the most relevant document
+being aggregated. This aggregator is intended to be used as a sub aggregator,
+so that the top matching documents can be aggregated per bucket.
+
+## Simple example
+
+```JSON
+{
+    "aggregation": {
+        "top-tags": {
+            "terms": {
+                "field": "tags",
+                "size": 3
+            },
+            "aggs": {
+                "top_tag_hits": {
+                    "top_hits": {
+                        "sort": [
+                            {
+                                "last_activity_date": {
+                                    "order": "desc"
+                                }
+                            }
+                        ],
+                        "_source": {
+                            "include": [
+                                "title"
+                            ]
+                        },
+                        "size" : 1
+                    }
+                }
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$sort = new Sort('last_activity_date', Sort::ORDER_DESC);
+$sorts = new Sorts();
+$sorts->addSort($sort);
+$topHitsAggregation = new TopHitsAggregation('top_tag_hits', 1, null, $sorts);
+$topHitsAggregation->addParameter('_source', ['include' => ['title']]);
+
+$termsAggregation = new TermsAggregation('top-tags', 'tags');
+$termsAggregation->addParameter('size', 3);
+$termsAggregation->addAggregation($topHitsAggregation);
+
+$search = new Search();
+$search->addAggregation($termsAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-top-hits-aggregation.html
diff --git a/docs/Aggregation/ValueCount.md b/docs/Aggregation/ValueCount.md
new file mode 100644
index 0000000000000000000000000000000000000000..359403ed207a449d03bd976f3ba83798b5c5b831
--- /dev/null
+++ b/docs/Aggregation/ValueCount.md
@@ -0,0 +1,28 @@
+# Value Count Aggregation
+
+> More info about value count aggregation is in the [official elasticsearch docs][1]
+
+A single-value metrics aggregation that counts the number of values that are extracted from the aggregated documents.
+
+## Simple example
+
+```JSON
+{
+    "aggs" : {
+        "grades_count" : { "value_count" : { "field" : "grade" } }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$valueCountAggregation = new ValueCountAggregation('grades_count', 'grade');
+
+$search = new Search();
+$search->addAggregation($valueCountAggregation);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-valuecount-aggregation.html
diff --git a/docs/Aggregation/index.md b/docs/Aggregation/index.md
new file mode 100644
index 0000000000000000000000000000000000000000..0d3bce5d90b8ba830ae1d7e2ec0d45ff6541f581
--- /dev/null
+++ b/docs/Aggregation/index.md
@@ -0,0 +1,110 @@
+# Aggregation
+
+Objective aggregation builder represents all available [Elasticsearch aggregations][1].
+
+
+To form an aggregation you have to create `Search` object. See below an example of min aggregation usage.
+
+```php
+$search = new Search();
+$minAggregation = new MinAggregation('min_agg');
+$minAggregation->setField('price');
+$search->addAggregation($minAggregation);
+$queryArray = $search->toArray();
+```
+
+There are 2 types of aggregation: bucketing and metric. The only difference in using them is that metric bucketing
+aggregations supports nesting while metric aggregations will ignore any set nested aggregations.
+
+## Nesting aggregations
+
+Bucketing aggregation can have any number nested aggregations and nesting can go to unlimited depth.
+
+Example nested aggregation.
+```JSON
+{
+    "aggregations": {
+        "agg_color": {
+            "terms": {
+                "field": "color"
+            },
+            "aggregations": {
+                "agg_avg_price": {
+                    "avg": {
+                        "field": "price"
+                    }
+                },
+                "agg_brand": {
+                    "terms": {
+                        "field": "brand"
+                    },
+                    "aggregations": {
+                        "agg_avg_price": {
+                            "avg": {
+                                "field": "price"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "agg_avg_price": {
+            "avg": {
+                "field": "price"
+            }
+        }
+    }
+}
+```
+
+```php
+$avgPriceAggregation = new AvgAggregation('avg_price');
+$avgPriceAggregation->setField('price');
+
+$brandTermAggregation = new TermsAggregation('brand');
+$brandTermAggregation->setField('brand');
+$brandTermAggregation->addAggregation($avgPriceAggregation);
+
+$colorTermsAggregation = new TermsAggregation('color');
+$colorTermsAggregation->setField('color');
+$colorTermsAggregation->addAggregation($avgPriceAggregation);
+$colorTermsAggregation->addAggregation($brandTermAggregation);
+
+$search = new Search();
+$search->addAggregation($colorTermsAggregation);
+$search->addAggregation($avgPriceAggregation);
+
+$queryArray = $search->toArray();
+```
+
+## Metric Aggregations
+ - [Avg](Avg.md)
+ - [Cardinality](Cardinality.md)
+ - [ExtendedStats](ExtendedStats.md)
+ - [Max](Max.md)
+ - [Min](Min.md)
+ - [PercentileRanks](PercentileRanks.md)
+ - [Percentiles](Percentiles.md)
+ - [Stats](Stats.md)
+ - [Sum](Sum.md)
+ - [TopHits](TopHits.md)
+ - [ValueCount](ValueCount.md)
+ 
+## Bucketing Aggregations
+ - [Children](Children.md)
+ - [DateRange](DateRange.md)
+ - [Filter](Filter.md)
+ - [Filters](Filters.md)
+ - [GeoBounds](GeoBounds.md)
+ - [GeoDistance](GeoDistance.md)
+ - [GeoHashGrid](GeoHashGrid.md)
+ - [Global](Global.md)
+ - [Histogram](Histogram.md)
+ - [Ipv4Range](Ipv4Range.md)
+ - [Missing](Missing.md)
+ - [Nested](Nested.md)
+ - [Range](Range.md)
+ - [ReverseNested](ReverseNested.md)
+ - [Terms](Terms.md)
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html
diff --git a/docs/Filter/And.md b/docs/Filter/And.md
new file mode 100644
index 0000000000000000000000000000000000000000..b514f8ed7424e50c2ca8ed6c9b09c02a0bc15042
--- /dev/null
+++ b/docs/Filter/And.md
@@ -0,0 +1,51 @@
+# And Filter
+
+> More info about and filter is in the [official elasticsearch docs][1]
+
+A filter that matches documents using the AND boolean operator on other filters.
+Can be placed within queries that accept a filter.
+
+## Simple example
+
+```JSON
+{
+    "filtered" : {
+        "query" : {
+            "term" : { "name.first" : "shay" }
+        },
+        "filter" : {
+            "and" : [
+                {
+                    "range" : {
+                        "postDate" : {
+                            "from" : "2010-03-01",
+                            "to" : "2010-04-01"
+                        }
+                    }
+                },
+                {
+                    "prefix" : { "name.second" : "ba" }
+                }
+            ]
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$rangeFilter = new RangeFilter('postDate', ['from' => '2010-03-01', 'to' => '2010-04-01']);
+$prefixFilter = new PrefixFilter('name.second', 'ba');
+$andFilter = new AndFilter([$rangeFilter, $prefixFilter]);
+
+$termQuery = new TermQuery('name.first', 'shay');
+
+$search = new Search();
+$search->addQuery($termQuery);
+$search->addFilter($andFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-and-filter.html
diff --git a/docs/Filter/Bool.md b/docs/Filter/Bool.md
new file mode 100644
index 0000000000000000000000000000000000000000..51bb746b025d6a60d54667de1a5a4e3d4658afe9
--- /dev/null
+++ b/docs/Filter/Bool.md
@@ -0,0 +1,96 @@
+# Bool Filter
+
+> More info about filter query is in the [official elasticsearch docs][1]
+
+A filter that matches documents matching boolean combinations of other queries. Similar in concept to
+[Boolean query][2], except that the clauses are other filters.
+
+To create a bool filter unlike other queries you don't have to create `BoolFilter` object. Just add queries to the
+search object and it will form bool filter automatically.
+
+Lets take an example to write a bool query with Elasticsearch DSL.
+
+```JSON
+{
+    "filtered" : {
+        "query" : {
+            "queryString" : {
+                "default_field" : "message",
+                "query" : "elasticsearch"
+            }
+        },
+        "filter" : {
+            "bool" : {
+                "must" : {
+                    "term" : { "tag" : "wow" }
+                },
+                "must_not" : {
+                    "range" : {
+                        "age" : { "gte" : 10, "lt" : 20 }
+                    }
+                },
+                "should" : [
+                    {
+                        "term" : { "tag" : "sometag" }
+                    },
+                    {
+                        "term" : { "tag" : "sometagtag" }
+                    }
+                ]
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$queryStringQuery = new QueryStringQuery('elasticsearch', ['default_field' => 'message']);
+
+$termFilter1 = new TermFilter('tag', 'wow');
+$rangeFilter = new RangeFilter('age', ['gte' => 10, 'lt' => 20]);
+$termFilter2 = new TermFilter('tag', 'sometag');
+$termFilter3 = new TermFilter('tag', 'sometagtag');
+
+$search = new Search();
+$search->addQuery($queryStringQuery);
+$search->addFilter($termFilter1);
+$search->addFilter($rangeFilter, BoolFilter::MUST_NOT);
+$search->addFilter($termFilter2, BoolFilter::SHOULD);
+$search->addFilter($termFilter3, BoolFilter::SHOULD);
+
+$queryArray = $search->toArray();
+```
+
+There is also an exception due adding filters to the search. If you add only one filter without type
+it will form simple query. e.g. lets try to create match all filter.
+
+```php
+$matchAllFilter = new MatchAllFilter();
+
+$search = new Search();
+$search->addFilter($matchAllFilter);
+
+$queryArray = $search->toArray();
+```
+
+You will get this query:
+```JSON
+{
+    "query": {
+        "filtered": {
+            "filter": {
+                "match_all": {}
+            }
+        }
+    }
+}
+```
+
+> More info about `Search` look in the [How to search](../HowTo/HowToSearch.md) chapter.
+
+
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-filter.html
+[2]: ../Query/Bool.md
\ No newline at end of file
diff --git a/docs/Filter/Exists.md b/docs/Filter/Exists.md
new file mode 100644
index 0000000000000000000000000000000000000000..c54434e3994e396e84ed630a481b1410f371587c
--- /dev/null
+++ b/docs/Filter/Exists.md
@@ -0,0 +1,31 @@
+# Exists Filter
+
+> More info about exists filter is in the [official elasticsearch docs][1]
+
+Returns documents that have at least one non-null value in the original field.
+
+## Simple example
+
+```JSON
+{
+    "constant_score" : {
+        "filter" : {
+            "exists" : { "field" : "user" }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$existsFilter = new ExistsFilter('user');
+$constantScoreQuery = new ConstantScoreQuery($existsFilter);
+
+$search = new Search();
+$search->addQuery($constantScoreQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-filter.html
diff --git a/docs/Filter/GeoBoundingBox.md b/docs/Filter/GeoBoundingBox.md
new file mode 100644
index 0000000000000000000000000000000000000000..2d3e23edc4d964286a21118ae59edd67c9754ad9
--- /dev/null
+++ b/docs/Filter/GeoBoundingBox.md
@@ -0,0 +1,90 @@
+# Geo Bounding Box Filter
+
+> More info about geo bounding box filter is in the [official elasticsearch docs][1]
+
+A filter allowing to filter hits based on a point location using a bounding box.
+
+## Simple example
+
+```JSON
+{
+    "filtered" : {
+        "query" : {
+            "match_all" : {}
+        },
+        "filter" : {
+            "geo_bounding_box" : {
+                "pin.location" : {
+                    "top_left" : {
+                        "lat" : 40.73,
+                        "lon" : -74.1
+                    },
+                    "bottom_right" : {
+                        "lat" : 40.01,
+                        "lon" : -71.12
+                    }
+                }
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$geoBoundingBoxFilter = new GeoBoundingBoxFilter(
+    'pin.location',
+    [
+        ['lat' => 40.73, 'lon' => -74.1],
+        ['lat' => 40.01, 'lon' => -74.12],
+    ]
+);
+
+$search = new Search();
+$search->addFilter($geoBoundingBoxFilter);
+
+$queryArray = $search->toArray();
+```
+
+Other format
+
+```JSON
+"filtered" : {
+    "query" : {
+        "match_all" : {}
+    },
+    "filter" : {
+        "geo_bounding_box" : {
+            "pin.location" : {
+                "top" : -74.1,
+                "left" : 40.73,
+                "bottom" : -71.12,
+                "right" : 40.01
+            }
+        }
+    }
+}
+```
+
+In DSL
+
+```php
+$geoBoundingBoxFilter = new GeoBoundingBoxFilter(
+    'pin.location',
+    [
+        -74.1,
+        40.73,
+        -71.12,
+        40.01,
+    ]
+);
+
+$search = new Search();
+$search->addFilter($geoBoundingBoxFilter);
+
+$queryArray = $search->toArray();
+```
+
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-bounding-box-filter.html
diff --git a/docs/Filter/GeoDistance.md b/docs/Filter/GeoDistance.md
new file mode 100644
index 0000000000000000000000000000000000000000..8c2ec11f36763c649b3176cc70f1db8edcd4ae7e
--- /dev/null
+++ b/docs/Filter/GeoDistance.md
@@ -0,0 +1,43 @@
+# Geo Distance Filter
+
+> More info about geo distance filter is in the [official elasticsearch docs][1]
+
+Filters documents that include only hits that exists within a specific distance from a geo point.
+
+## Simple example
+
+```JSON
+{
+    "filtered" : {
+        "query" : {
+            "match_all" : {}
+        },
+        "filter" : {
+            "geo_distance" : {
+                "distance" : "200km",
+                "pin.location" : {
+                    "lat" : 40,
+                    "lon" : -70
+                }
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$geoDistanceFilter = new GeoDistanceFilter(
+    'pin.location',
+    '200km',
+    ['lat' => 40, 'lon' => -70]
+);
+
+$search = new Search();
+$search->addFilter($geoDistanceFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-filter.html
diff --git a/docs/Filter/GeoDistanceRange.md b/docs/Filter/GeoDistanceRange.md
new file mode 100644
index 0000000000000000000000000000000000000000..ccb692c0e7b95f42dc2b18de1ba08ccfbd921a83
--- /dev/null
+++ b/docs/Filter/GeoDistanceRange.md
@@ -0,0 +1,45 @@
+# Geo Distance Range Filter
+
+> More info about geo distance range filter is in the [official elasticsearch docs][1]
+
+Filters documents that exists within a range from a specific point.
+
+## Simple example
+
+```JSON
+{
+    "filtered" : {
+        "query" : {
+            "match_all" : {}
+        },
+        "filter" : {
+            "geo_distance_range" : {
+                "from" : "200km",
+                "to" : "400km",
+                "pin.location" : {
+                    "lat" : 40,
+                    "lon" : -70
+                }
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$geoDistanceRangeFilter = new GeoDistanceRangeFilter(
+    'pin.location',
+    ['from' => '200km', 'to' => '400km'],
+    ['lat' => 40, 'lon' => -70]
+);
+
+$search = new Search();
+$search->addFilter($geoDistanceRangeFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-range-filter.html
+
diff --git a/docs/Filter/GeoPolygon.md b/docs/Filter/GeoPolygon.md
new file mode 100644
index 0000000000000000000000000000000000000000..98631f16fc8f573c8a65c6c0c09da38f90500dbb
--- /dev/null
+++ b/docs/Filter/GeoPolygon.md
@@ -0,0 +1,48 @@
+# Geo Polygon Filter
+
+> More info about geo polygon range filter is in the [official elasticsearch docs][1]
+
+A filter allowing to include hits that only fall within a polygon of points.
+
+## Simple example
+
+```JSON
+{
+    "filtered" : {
+        "query" : {
+            "match_all" : {}
+        },
+        "filter" : {
+            "geo_polygon" : {
+                "person.location" : {
+                    "points" : [
+                        {"lat" : 40, "lon" : -70},
+                        {"lat" : 30, "lon" : -80},
+                        {"lat" : 20, "lon" : -90}
+                    ]
+                }
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$geoPolygonFilter = new GeoPolygonFilter(
+    'person.location',
+    [
+        ['lat' => 40, 'lon' => -70],
+        ['lat' => 30, 'lon' => -80],
+        ['lat' => 20, 'lon' => -90],
+    ]
+);
+
+$search = new Search();
+$search->addFilter($geoPolygonFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-polygon-filter.html
diff --git a/docs/Filter/GeoShape.md b/docs/Filter/GeoShape.md
new file mode 100644
index 0000000000000000000000000000000000000000..e44d81696d08d5b7d9657ffa07c849a3340b055f
--- /dev/null
+++ b/docs/Filter/GeoShape.md
@@ -0,0 +1,86 @@
+# Geo Shape Filter
+
+> More info about geo shape filter is in the [official elasticsearch docs][1]
+
+Filter documents indexed using the geo shape type.
+
+## Simple example
+
+```JSON
+{
+    "query":{
+        "filtered": {
+            "query": {
+                "match_all": {}
+            },
+            "filter": {
+                "geo_shape": {
+                    "location": {
+                        "shape": {
+                            "type": "envelope",
+                            "coordinates" : [[13.0, 53.0], [14.0, 52.0]]
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$geoShapeFilter = new GeoShapeFilter();
+$geoShapeFilter->addShape('location', 'envelope', [[13.0, 53.0], [14.0, 52.0]]);
+
+$search = new Search();
+$search->addFilter($geoShapeFilter);
+
+$queryArray = $search->toArray();
+```
+
+## Pre Indexed Shape
+
+```JSON
+{
+    "filtered": {
+        "query": {
+            "match_all": {}
+        },
+        "filter": {
+            "geo_shape": {
+                "location": {
+                    "indexed_shape": {
+                        "id": "DEU",
+                        "type": "countries",
+                        "index": "shapes",
+                        "path": "location"
+                    }
+                }
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$geoShapeFilter = new GeoShapeFilter();
+$geoShapeFilter->addPreIndexedShape(
+    'location',
+    'DEU',
+    'countries',
+    'shapes',
+    'location'
+);
+
+$search = new Search();
+$search->addFilter($geoShapeFilter);
+
+$queryArray = $search->toArray();
+```
+
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-shape-filter.html
diff --git a/docs/Filter/GeohashCell.md b/docs/Filter/GeohashCell.md
new file mode 100644
index 0000000000000000000000000000000000000000..25edda7827fe427d6621ca12b990bc1fa25c0dbf
--- /dev/null
+++ b/docs/Filter/GeohashCell.md
@@ -0,0 +1,51 @@
+# Geohash Cell Filter
+
+> More info about geohash cell filter is in the [official elasticsearch docs][1]
+
+The geohash cell filter provides access to a hierarchy of geohashes.
+By defining a geohash cell, only geopoints within this cell will match this filter.
+
+## Simple example
+
+```JSON
+{
+    "filtered" : {
+        "query" : {
+            "match_all" : {}
+        },
+        "filter" : {
+            "geohash_cell": {
+                "pin": {
+                    "lat": 13.4080,
+                    "lon": 52.5186
+                },
+                "precision": 3,
+                "neighbors": true
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$geohashCellFilter = new GeohashCellFilter(
+    'pin',
+    [
+        'lat' => 13.4080,
+        'lon' => 52.5186,
+    ],
+    [
+        'precision' => 3,
+        'neighbors' => true,
+    ]
+);
+
+$search = new Search();
+$search->addFilter($geohashCellFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geohash-cell-filter.html
diff --git a/docs/Filter/HasChild.md b/docs/Filter/HasChild.md
new file mode 100644
index 0000000000000000000000000000000000000000..7ea66912261a7024dcad30b05bbc5b0625e37599
--- /dev/null
+++ b/docs/Filter/HasChild.md
@@ -0,0 +1,38 @@
+# Has Child Filter
+
+> More info about has child filter is in the [official elasticsearch docs][1]
+
+The has child filter accepts a query and the child type to run against,
+and results in parent documents that have child docs matching the query.
+
+## Simple example
+
+```JSON
+{
+    "has_child" : {
+        "type" : "blog_tag",
+        "query" : {
+            "term" : {
+                "tag" : "something"
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termQuery = new TermQuery('tag', 'something');
+$hasChildFilter = new HasChildFilter(
+    'blog_tag',
+    $termQuery
+);
+
+$search = new Search();
+$search->addFilter($hasChildFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-child-filter.html
diff --git a/docs/Filter/HasParent.md b/docs/Filter/HasParent.md
new file mode 100644
index 0000000000000000000000000000000000000000..53bd7fa2454a86f715c53f4c20538e2b0874eed2
--- /dev/null
+++ b/docs/Filter/HasParent.md
@@ -0,0 +1,39 @@
+# Has Parent Filter
+
+> More info about has parent filter is in the [official elasticsearch docs][1]
+
+The has parent filter accepts a query and a parent type.
+The query is executed in the parent document space, which is specified by the parent type.
+This filter returns child documents which associated parents have matched.
+
+## Simple example
+
+```JSON
+{
+    "has_child" : {
+        "type" : "blog_tag",
+        "query" : {
+            "term" : {
+                "tag" : "something"
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termQuery = new TermQuery('tag', 'something');
+$hasParentFilter = new HasParentFilter(
+    'blog',
+    $termQuery
+);
+
+$search = new Search();
+$search->addFilter($hasParentFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-parent-filter.html
diff --git a/docs/Filter/Ids.md b/docs/Filter/Ids.md
new file mode 100644
index 0000000000000000000000000000000000000000..e2bcfb6ed8e2dc51b4cb1589546ae4c6e6bb733c
--- /dev/null
+++ b/docs/Filter/Ids.md
@@ -0,0 +1,32 @@
+# Ids Filter
+
+> More info about ids filter is in the [official elasticsearch docs][1]
+
+Filters documents that only have the provided ids.
+
+## Simple example
+
+```JSON
+{
+    "ids" : {
+        "type" : "my_type",
+        "values" : ["1", "4", "100"]
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$idsFilters = new IdsFilter(
+    ['1', '4', '100'],
+    ['type' => 'my_type']
+);
+
+$search = new Search();
+$search->addFilter($idsFilters);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-ids-filter.html
diff --git a/docs/Filter/Indices.md b/docs/Filter/Indices.md
new file mode 100644
index 0000000000000000000000000000000000000000..caacb11fd90617f103d5b1578cdc08caa8456143
--- /dev/null
+++ b/docs/Filter/Indices.md
@@ -0,0 +1,45 @@
+# Indices Filter
+
+> More info about indices filter is in the [official elasticsearch docs][1]
+
+The indices filter can be used when executed across multiple indices,
+allowing to have a filter that executes only when executed on an index
+that matches a specific list of indices, and another filter that
+executes when it is executed on an index that does not match the listed
+indices.
+
+## Simple example
+
+```JSON
+{
+    "indices" : {
+        "indices" : ["index1", "index2"],
+        "filter" : {
+            "term" : { "tag" : "wow" }
+        },
+        "no_match_filter" : {
+            "term" : { "tag" : "kow" }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termFilter1 = new TermFilter('tag', 'wow');
+$termFilter2 = new TermFilter('tag', 'kow');
+
+$indicesFilter = new IndicesFilter(
+    ['index1', 'index2'],
+    $termFilter1,
+    $termFilter2
+);
+
+$search = new Search();
+$search->addFilter($indicesFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-indices-filter.html
diff --git a/docs/Filter/Limit.md b/docs/Filter/Limit.md
new file mode 100644
index 0000000000000000000000000000000000000000..567be0fb817ec5d15cc974492682782d3a1db4af
--- /dev/null
+++ b/docs/Filter/Limit.md
@@ -0,0 +1,35 @@
+# Limit Filter
+
+> More info about limit filter is in the [official elasticsearch docs][1]
+
+A limit filter limits the number of documents (per shard) to execute on.
+
+## Simple example
+
+```JSON
+{
+    "filtered" : {
+        "filter" : {
+             "limit" : {"value" : 100}
+         },
+         "query" : {
+            "term" : { "name.first" : "shay" }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$limitFilter = new LimitFilter(100);
+$termQuery = new TermQuery('name.first', 'shay');
+
+$filteredQuery = new FilteredQuery($termQuery, $limitFilter);
+
+$search = new Search();
+$search->addQuery($filteredQuery);
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-limit-filter.html
diff --git a/docs/Filter/MatchAll.md b/docs/Filter/MatchAll.md
new file mode 100644
index 0000000000000000000000000000000000000000..3d8d9ed61a78a765f033bf7f6a485f67347a271e
--- /dev/null
+++ b/docs/Filter/MatchAll.md
@@ -0,0 +1,28 @@
+# Match All Filter
+
+> More info about match all filter is in the [official elasticsearch docs][1]
+
+A filter that matches on all documents.
+
+## Simple example
+
+```JSON
+{
+    "filter" : {
+        "match_all" : { }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$matchAllFilter = new MatchAllFilter();
+
+$search = new Search();
+$search->addFilter($matchAllFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-indices-filter.html
diff --git a/docs/Filter/Missing.md b/docs/Filter/Missing.md
new file mode 100644
index 0000000000000000000000000000000000000000..f963111bac2932d739b85853bb209ec4748c6ae8
--- /dev/null
+++ b/docs/Filter/Missing.md
@@ -0,0 +1,28 @@
+# Missing Filter
+
+> More info about missing filter is in the [official elasticsearch docs][1]
+
+Returns documents that have only null values or no value in the original field.
+
+## Simple example
+
+```JSON
+{
+    "filter" : {
+        "missing" : { "field" : "user" }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$missingFilter = new MissingFilter('user');
+
+$search = new Search();
+$search->addFilter($missingFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: hhttps://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-missing-filter.html
diff --git a/docs/Filter/Nested.md b/docs/Filter/Nested.md
new file mode 100644
index 0000000000000000000000000000000000000000..151ac121d296b0dbf45565347fad8213d323251a
--- /dev/null
+++ b/docs/Filter/Nested.md
@@ -0,0 +1,56 @@
+# Nested Filter
+
+> More info about nested filter is in the [official elasticsearch docs][1]
+
+Nested filter allows to filter nested objects / documents (see nested mapping).
+The filter is executed against the nested objects / documents as if they
+were indexed as separate documents (they are, internally) and resulting
+in the root parent doc (or parent nested mapping).
+
+## Simple example
+
+```JSON
+{
+    "filtered" : {
+        "query" : { "match_all" : {} },
+        "filter" : {
+            "nested" : {
+                "path" : "obj1",
+                "filter" : {
+                    "bool" : {
+                        "must" : [
+                            {
+                                "term" : {"obj1.name" : "blue"}
+                            },
+                            {
+                                "range" : {"obj1.count" : {"gt" : 5}}
+                            }
+                        ]
+                    }
+                },
+                "_cache" : true
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termFilter = new TermFilter('obj1.name', 'blue');
+$rangeFilter = new RangeFilter('obj1.count', ['gt' => 5]);
+
+$boolFilter = new BoolFilter();
+$boolFilter->add($termFilter);
+$boolFilter->add($rangeFilter);
+
+$nestedFilter = new NestedFilter('obj1', $boolFilter, ['_cache' => true]);
+
+$search = new Search();
+$search->addFilter($nestedFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-filter.html
diff --git a/docs/Filter/Not.md b/docs/Filter/Not.md
new file mode 100644
index 0000000000000000000000000000000000000000..9fc9697af7bb519e091593f41892755fa1bd6b82
--- /dev/null
+++ b/docs/Filter/Not.md
@@ -0,0 +1,50 @@
+# Not Filter
+
+> More info about not filter is in the [official elasticsearch docs][1]
+
+A filter that filters out matched documents using a query.
+
+## Simple example
+
+```JSON
+{
+    "filtered" : {
+        "query" : {
+            "term" : { "name.first" : "shay" }
+        },
+        "filter" : {
+            "not" : {
+                "range" : {
+                    "postDate" : {
+                        "from" : "2010-03-01",
+                        "to" : "2010-04-01"
+                    }
+                }
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$rangeFilter = new RangeFilter(
+    'postDate',
+    [
+        'from' => '2010-03-01',
+        'to' => '2010-04-01',
+    ]
+);
+
+$notFilter = new NotFilter($rangeFilter);
+
+$termQuery = new TermQuery('name.first', 'shay');
+$filteredQuery = new FilteredQuery($termQuery, $notFilter);
+
+$search = new Search();
+$search->addQuery($filteredQuery);
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-not-filter.html
diff --git a/docs/Filter/Or.md b/docs/Filter/Or.md
new file mode 100644
index 0000000000000000000000000000000000000000..7c8ef3c7ecf57009a0b9a57eedccf533231f94e0
--- /dev/null
+++ b/docs/Filter/Or.md
@@ -0,0 +1,47 @@
+# Or Filter
+
+> More info about or filter is in the [official elasticsearch docs][1]
+
+A filter that matches documents using the OR boolean operator on other filters.
+
+## Simple example
+
+```JSON
+{
+    "filtered" : {
+        "query" : {
+            "term" : { "name.first" : "shay" }
+        },
+        "filter" : {
+            "or" : [
+                {
+                    "term" : { "name.second" : "banon" }
+                },
+                {
+                    "term" : { "name.nick" : "kimchy" }
+                }
+            ]
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termFilter1 = new TermFilter('name.second', 'banon');
+$termFilter2 = new TermFilter('name.nick', 'kimchy');
+
+$orFilter = new OrFilter();
+$orFilter->add($termFilter1);
+$orFilter->add($termFilter2);
+
+$termQuery = new TermQuery('name.first', 'shay');
+$filteredQuery = new FilteredQuery($termQuery, $orFilter);
+
+$search = new Search();
+$search->addQuery($filteredQuery);
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-or-filter.html
diff --git a/docs/Filter/Post.md b/docs/Filter/Post.md
new file mode 100644
index 0000000000000000000000000000000000000000..c976c26b7f976f9b04ddf665da95973c0ddea632
--- /dev/null
+++ b/docs/Filter/Post.md
@@ -0,0 +1,69 @@
+# Post Filter
+
+> More info about post filter is in the [official elasticsearch docs][1]
+
+The post filters are filters that are applied to the search hits at the very end
+of a search request, after [aggregations][2] have already been calculated.
+
+To add post filters use `addPostFilter` method in `Search` object.
+`addPostFilter` works like query and filter adders - you can add as many
+filters as you want and bool filter will be formed if endpoint has multiple
+filters or bool type parameter was provided.
+
+## Simple example
+
+```JSON
+{
+  "post_filter": { 
+    "term": { "color": "red" }
+  }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termFilter = new TermFilter('color', 'red');
+
+$search = new Search();
+$search->addPostFilter($termFilter);
+$queryArray = $search->toArray();
+```
+
+## Bool example
+
+```JSON
+{
+    "post_filter": {
+        "bool": {
+            "must": [
+                {
+                    "term": {
+                        "color": "red"
+                    }
+                },
+                {
+                    "term": {
+                        "brand": "ana"
+                    }
+                }
+            ]
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termFilter1 = new TermFilter('color', 'red');
+$termFilter2 = new TermFilter('brand', 'ana');
+
+$search = new Search();
+$search->addPostFilter($termFilter1);
+$search->addPostFilter($termFilter2);
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-post-filter.html
+[2]: ../Aggregation/index.md
\ No newline at end of file
diff --git a/docs/Filter/Prefix.md b/docs/Filter/Prefix.md
new file mode 100644
index 0000000000000000000000000000000000000000..75e541c43209c3675c7a843d8738e30ad49fa970
--- /dev/null
+++ b/docs/Filter/Prefix.md
@@ -0,0 +1,28 @@
+# Prefix Filter
+
+> More info about prefix filter is in the [official elasticsearch docs][1]
+
+Filters documents that have fields containing terms with a specified prefix.
+
+## Simple example
+
+```JSON
+{
+    "filter" : {
+        "prefix" : { "user" : "ki" }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termFilter = new PrefixFilter('user', 'ki');
+
+$search = new Search();
+$search->addFilter($termFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-filter.html
diff --git a/docs/Filter/Query.md b/docs/Filter/Query.md
new file mode 100644
index 0000000000000000000000000000000000000000..0889b83cfab46c3a67e8671032cfb504d6296327
--- /dev/null
+++ b/docs/Filter/Query.md
@@ -0,0 +1,33 @@
+# Query Filter
+
+> More info about query filter is in the [official elasticsearch docs][1]
+
+Wraps any query to be used as a filter.
+
+## Simple example
+
+```JSON
+{
+    "filter" : {
+        "query" : {
+            "query_string" : {
+                "query" : "this AND that OR thus"
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$queryStringQuery = new QueryStringQuery('this AND that OR thus');
+$queryFilter = new QueryFilter($queryStringQuery);
+
+$search = new Search();
+$search->addFilter($queryFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-filter.html
diff --git a/docs/Filter/Range.md b/docs/Filter/Range.md
new file mode 100644
index 0000000000000000000000000000000000000000..e2a2315be5beaefe2f0a28c192d3e7727598b4e4
--- /dev/null
+++ b/docs/Filter/Range.md
@@ -0,0 +1,33 @@
+# Range Filter
+
+> More info about range filter is in the [official elasticsearch docs][1]
+
+Filters documents with fields that have terms within a certain range.
+
+## Simple example
+
+```JSON
+{
+    "filter" : {
+        "range" : {
+            "age" : {
+                "gte": 10,
+                "lte": 20
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$rangeFilter = new RangeFilter('age', ['gte' => 10, 'lte' => 20]);
+
+$search = new Search();
+$search->addFilter($rangeFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-filter.html
diff --git a/docs/Filter/Regexp.md b/docs/Filter/Regexp.md
new file mode 100644
index 0000000000000000000000000000000000000000..99e8c031375a3d2b224857c686d11607799af370
--- /dev/null
+++ b/docs/Filter/Regexp.md
@@ -0,0 +1,32 @@
+# Regexp Filter
+
+> More info about regexp filter is in the [official elasticsearch docs][1]
+
+The regexp filter allows you to use regular expression term queries.
+The regexp filter is similar to the [regexp query][2],
+except that it is cacheable and can speedup performance in case you are
+reusing this filter in your queries.
+
+## Simple example
+
+```JSON
+{
+    "regexp":{
+        "name.first": "s.*y"
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$regexpFilter = new RegexpFilter('name.first', 's.*y');
+
+$search = new Search();
+$search->addFilter($regexpFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-indices-filter.html
+[2]: ../Query/Regexp.md
\ No newline at end of file
diff --git a/docs/Filter/Script.md b/docs/Filter/Script.md
new file mode 100644
index 0000000000000000000000000000000000000000..8d35342c7ce1cc92d89eaa76abf30142a2a65db3
--- /dev/null
+++ b/docs/Filter/Script.md
@@ -0,0 +1,30 @@
+# Script Filter
+
+> More info about script filter is in the [official elasticsearch docs][1]
+
+A filter allowing to define scripts as filters
+
+## Simple example
+
+```JSON
+{
+    "filter" : {
+        "script" : {
+            "script" : "doc['num1'].value > 1"
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$scriptFilter = new ScriptFilter('doc[\'num1\'].value > 1');
+
+$search = new Search();
+$search->addFilter($scriptFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-script-filter.html
diff --git a/docs/Filter/Term.md b/docs/Filter/Term.md
new file mode 100644
index 0000000000000000000000000000000000000000..15a482a2ecdc630bea457d060960a5dc4ae2594f
--- /dev/null
+++ b/docs/Filter/Term.md
@@ -0,0 +1,28 @@
+# Term Filter
+
+> More info about term filter is in the [official elasticsearch docs][1]
+
+Filters documents that have fields that contain a term.
+
+## Simple example
+
+```JSON
+{
+    "filter" : {
+        "term" : { "user" : "kimchy"}
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termFilter = new TermFilter('user', 'kimchy');
+
+$search = new Search();
+$search->addFilter($termFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-filter.html
diff --git a/docs/Filter/Terms.md b/docs/Filter/Terms.md
new file mode 100644
index 0000000000000000000000000000000000000000..6b595ba0c95d6c18fd67c98a066f607234112b50
--- /dev/null
+++ b/docs/Filter/Terms.md
@@ -0,0 +1,28 @@
+# Terms Filter
+
+> More info about terms filter is in the [official elasticsearch docs][1]
+
+Filters documents that have fields that match any of the provided terms.
+
+## Simple example
+
+```JSON
+{
+    "filter" : {
+       "terms" : { "user" : ["kimchy", "elasticsearch"]}
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termsFilter = new TermsFilter('user', ['kimchy', 'elasticsearch']);
+
+$search = new Search();
+$search->addFilter($termsFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-filter.html
diff --git a/docs/Filter/Type.md b/docs/Filter/Type.md
new file mode 100644
index 0000000000000000000000000000000000000000..91915efb8683c90d5e6f7334d54b8c098505976d
--- /dev/null
+++ b/docs/Filter/Type.md
@@ -0,0 +1,28 @@
+# Type Filter
+
+> More info about type filter is in the [official elasticsearch docs][1]
+
+Filters documents matching the provided document / mapping type.
+
+## Simple example
+
+```JSON
+{
+    "type" : {
+        "value" : "my_type"
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$typeFilter = new TypeFilter('my_type');
+
+$search = new Search();
+$search->addFilter($typeFilter);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-type-filter.html
diff --git a/docs/Filter/index.md b/docs/Filter/index.md
new file mode 100644
index 0000000000000000000000000000000000000000..284c08950fb45751542bbb087f509abece950e56
--- /dev/null
+++ b/docs/Filter/index.md
@@ -0,0 +1,63 @@
+# Query
+
+Objective filter builder represents all available [Elasticsearch filters][1].
+
+To form a filtered query you have to create `Search` object. See below an example of match all filter usage.
+
+```php
+$search = new Search();
+$matchAllFilter = new MatchAllFilter();
+$search->addFilter($matchAllFilter);
+$queryArray = $search->toArray();
+```
+
+Filters handles are necessary little things like where to put `\stdClass` and where to simple array. So by using DSL builder you can be always sure that it will form a correct query.
+
+Here's `$queryArray` var_dump:
+
+```php
+//$queryArray content
+'query' => [
+        'filtered' => [
+            'filter' => [
+                'match_all' => \stdClass(),
+            ]
+        ]
+    ]
+```
+
+For more information how to combine search queries take a look at [How to search](../HowTo/HowToSearch.md) chapter.
+
+
+## Filters:
+ - [And](And.md)
+ - [Bool](Bool.md)
+ - [Exists](Exists.md)
+ - [GeoBoundingBox](GeoBoundingBox.md)
+ - [GeoDistance](GeoDistance.md)
+ - [GeoDistanceRange](GeoDistanceRange.md)
+ - [GeoPolygon](GeoPolygon.md)
+ - [GeoShape](GeoShape.md)
+ - [GeohashCell](GeohashCell.md)
+ - [HasChild](HasChild.md)
+ - [HasParent](HasParent.md)
+ - [Ids](Ids.md)
+ - [Indices](Indices.md)
+ - [Limit](Limit.md)
+ - [MatchAll](MatchAll.md)
+ - [Missing](Missing.md)
+ - [Nested](Nested.md)
+ - [Not](Not.md)
+ - [Or](Or.md)
+ - [Post](Post.md)
+ - [Prefix](Prefix.md)
+ - [Query](Query.md)
+ - [Range](Range.md)
+ - [Regexp](Regexp.md)
+ - [Script](Script.md)
+ - [Term](Term.md)
+ - [Terms](Terms.md)
+ - [Type](Type.md)
+
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-filters.html
diff --git a/docs/HowTo/HowToSearch.md b/docs/HowTo/HowToSearch.md
new file mode 100644
index 0000000000000000000000000000000000000000..d1e95c8e18920e9cffdb37fa0d175b9b13ac72a5
--- /dev/null
+++ b/docs/HowTo/HowToSearch.md
@@ -0,0 +1,180 @@
+# How to search with Elasticsearch DSL
+
+In this chapter we will take a look how to perform a search via objective way with Elasticsearch DSL. Well, the good news is that is very simple. That's why we created this library ;).
+
+To start a search you have to create a `Search` object.
+
+```php
+$search = new Search();
+```
+
+> We won't include namespaces in any examples. Don't worry all class's names are unique, so any IDE editor should autocomplete and include it for you ;).
+
+So, when we have a `Search` object we can start add something to it. Usually you will add `Query`, `Filter` and `Aggregation`.
+
+> More info how create [queries](../Query/index.md), [filters](../Filter/index.md) and [aggregations](../Aggregation/index.md) objects.
+
+### Form a Query
+
+Lets take a simple query example with `MatchAllQuery`.
+
+```php
+$matchAllQuery = new MatchAllQuery();
+```
+
+To add query to the `Search` simply call `addQuery` function.
+
+```php
+$search->addQuery($matchAllQuery);
+```
+
+At the end it will form this query:
+
+```JSON
+{
+  "query": {
+      "match_all": {}
+  }
+}
+```
+
+
+> There is no limits to add queries or filters or anything.
+
+### Form a Filter
+
+To add a filter is the same way like a query. First, lets create some `Filter` object.
+
+```php
+$matchAllFilter = new MatchAllFilter();
+```
+
+And simply add to the `Search`:
+
+```php
+$search->addFilter($matchAllFilter);
+```
+
+Unlike `Query`, when we add a `Filter` with our DSL library it will add a query and all necessary stuff for you. So when we add one filter we will get this query:
+
+```JSON
+{
+  "query": {
+      "filtered": {
+          "filter": {
+              "match_all": {}
+          }
+      }
+  }
+}
+```
+
+### Multiple queries and filters
+
+As you know there is possible to use multiple filters and queries in elasticsearch. No problem, if you have several filters just add it to the search. `ElasticsearchDSL` will form a `Bool` query or filter for you when you add more than one.
+
+Lets take an example with `Query`:
+
+```php
+$search = new Search();
+$termQueryForTag1 = new TermQuery("tag", "wow");
+$termQueryForTag2 = new TermQuery("tag", "elasticsearch");
+$termQueryForTag3 = new TermQuery("tag", "dsl");
+
+$search->addQuery($termQueryForTag1);
+$search->addQuery($termQueryForTag2);
+$search->addQuery($termQueryForTag3, BoolQuery::SHOULD);
+```
+The query will look like:
+
+```JSON
+{
+  "query": {
+    "bool": {
+        "must": [
+            {
+                "term": { "tag": "wow" }
+            },
+            {
+                "term": { "tag": "elasticsearch" }
+            }
+        ]
+        "should": [
+            {
+                "term": { "tag": "dsl" }
+            }
+        ]
+    }
+  }
+}
+```
+> More info how to form bool queries find in [Bool Query](../Query/Bool.md) chapter.
+
+The same way it works with a `Filter`. Take a look at this example:
+
+```php
+$search = new Search();
+$termFilter = new TermFilter('name', 'ongr');
+$missingFilter = new MissingFilter('disabled');
+$existsFilter = new ExistsFilter('tag');
+$search->addFilter($termFilter);
+$search->addFilter($missingFilter);
+$search->addFilter($existsFilter, BoolFilter::MUST_NOT);
+```
+
+Elasticsearch DSL will form this query:
+
+```JSON
+{
+  "query": {
+    "filtered": {
+        "filter": {
+            "bool": {
+                "must": [
+                    {
+                        "term": {
+                            "name": "ongr"
+                        }
+                    },
+                    {
+                        "missing": {
+                            "field": "disabled"
+                        }
+                    }
+                ],
+                "must_not": [
+                    {
+                        "exists": {
+                            "field": "tag"
+                        }
+                    }
+                ]
+            }
+        }
+    }
+  }
+}
+```
+
+### Modify queries
+
+
+
+
+### Sent request to the elasticsearch
+And finaly we can pass it to `elasticsearch-php` client. To generate an array for the client we call `toArray()` function.
+
+```php
+//from elasticsearch/elasticsearch package
+$client = new Elasticsearch\Client();
+
+$searchParams = [
+  'index' => 'people',
+  'type' => 'person',
+  'body' => $search->toArray(),
+];
+
+$docs = $client->search($searchParams);
+```
+
+> This example is for elasticsearch/elasticsearch ~1.0 version.
diff --git a/docs/Query/Bool.md b/docs/Query/Bool.md
new file mode 100644
index 0000000000000000000000000000000000000000..f3182435275f3c29519920b2f896253bc41910e2
--- /dev/null
+++ b/docs/Query/Bool.md
@@ -0,0 +1,76 @@
+# Bool query
+
+> More info about Bool query is in the [official elasticsearch docs][1]
+
+It's a query that matches documents matching boolean combinations of other queries.
+
+To create a bool query unlike other queries you don't have to create `BoolQuery` object. Just add queries to the search object and it will form bool query automatically.
+
+Lets take an example to write a bool query with Elasticsearch DSL.
+
+```JSON
+{
+    "bool" : {
+        "must" : {
+            "term" : { "user" : "kimchy" }
+        },
+        "must_not" : {
+            "range" : {
+                "age" : { "from" : 10, "to" : 20 }
+            }
+        },
+        "should" : [
+            {
+                "term" : { "tag" : "wow" }
+            },
+            {
+                "term" : { "tag" : "elasticsearch" }
+            }
+        ],
+        "minimum_should_match" : 1,
+        "boost" : 1.0
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termQueryForUser = new TermQuery("user", "kimchy");
+$termQueryForTag1 = new TermQuery("tag", "wow");
+$termQueryForTag2 = new TermQuery("tag", "elasticsearch");
+$rangeQuery = new RangeQuery("age", ["from" => 10, "to" => 20]);
+
+$search = new Search();
+$search->addQuery($termQueryForUser, BoolQuery::MUST);
+$search->addQuery($rangeQuery, BoolQuery::MUST_NOT);
+$search->addQuery($termQueryForTag1, BoolQuery::SHOULD);
+$search->addQuery($termQueryForTag2, BoolQuery::SHOULD);
+$search->setBoolQueryParameters(["minimum_should_match" => 1, "boost" => 1]);
+
+$queryArray = $search->toArray();
+```
+
+There is also an exception due adding queries to the search. If you add only one query without type it will form simple query. e.g. lets try to create match all query.
+
+```php
+$search = new Search();
+$matchAllQuery = new MatchAllQuery();
+$search->addQuery($matchAllQuery);
+$queryArray = $search->toArray();
+```
+
+You will get this query:
+```JSON
+{
+    "query": {
+        "match_all": {}
+    }
+}
+```
+
+> More info about `Search` look in the [How to search](../HowTo/HowToSearch.md) chapter.
+
+
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html
diff --git a/docs/Query/Boosting.md b/docs/Query/Boosting.md
new file mode 100644
index 0000000000000000000000000000000000000000..497a3def39e699f9f196f95f937eceaf39dcca4b
--- /dev/null
+++ b/docs/Query/Boosting.md
@@ -0,0 +1,40 @@
+# Boosting query
+
+> More info about Boosting query is in the [official elasticsearch docs][1]
+
+Lets take an example to write a query with Elasticsearch DSL.
+
+```JSON
+{
+    "boosting" : {
+        "positive" : {
+            "term" : {
+                "field1" : "value1"
+            }
+        },
+        "negative" : {
+            "term" : {
+                "field2" : "value2"
+            }
+        },
+        "negative_boost" : 0.2
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termQuery1 = new TermQuery("field1", "value1");
+$termQuery2 = new TermQuery("field2", "value2");
+
+$boostingQuery = new BoostingQuery($termQuery1, $termQuery2, 0.2);
+
+$search = new Search();
+$search->addQuery($boostingQuery);
+
+$queryArray = $search->toArray();
+```
+
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-boosting-query.html
diff --git a/docs/Query/CommonTerms.md b/docs/Query/CommonTerms.md
new file mode 100644
index 0000000000000000000000000000000000000000..a2307a3a7d1270cc3fb619a815e54f4c1f6b15c1
--- /dev/null
+++ b/docs/Query/CommonTerms.md
@@ -0,0 +1,46 @@
+# Common terms query
+
+> More info about Common terms query is in the [official elasticsearch docs][1]
+
+There are so many use cases with `Common Terms` query. We highly recommend to take a look at the [official docs][1] before continuing.
+
+Lets take first example to write easy `Common query` with Elasticsearch DSL.
+
+```JSON
+{
+  "common": {
+    "name": {
+      "query": "this is bonsai cool",
+      "cutoff_frequency": 0.001,
+      "minimum_should_match": {
+          "low_freq" : 2,
+          "high_freq" : 3
+       }
+    }
+  }
+}
+```
+
+And now the query via DSL:
+
+```php
+$commonTermsQuery = new CommonTermsQuery(
+    "field_name",
+    "this is bonsai cool",
+    [
+        "cutoff_frequency" => 0.001,
+        "minimum_should_match" => [
+          "low_freq" => 2,
+          "high_freq" => 3,
+        ],
+    ]
+);
+
+$search = new Search();
+$search->addQuery($commonTermsQuery);
+
+$queryArray = $search->toArray();
+```
+
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-common-terms-query.html
diff --git a/docs/Query/ConstantScore.md b/docs/Query/ConstantScore.md
new file mode 100644
index 0000000000000000000000000000000000000000..dda1c0dad55fbb071c4c262c076f71c28a15c660
--- /dev/null
+++ b/docs/Query/ConstantScore.md
@@ -0,0 +1,58 @@
+# Constant score query
+
+> More info about Constant score query is in the [official elasticsearch docs][1]
+
+Inside constant score query you can insert filter or query.
+
+Lets take an example to write a constant score query with filter inside.
+
+```JSON
+{
+    "constant_score" : {
+        "filter" : {
+            "term" : { "user" : "kimchy"}
+        },
+        "boost" : 1.2
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$termFilter = new TermFilter("user", "kimchy");
+$constantScoreQuery = new ConstantScoreQuery($termFilter, ["boost" => 1.2]);
+
+$search = new Search();
+$search->addQuery($constantScoreQuery);
+
+$queryArray = $search->toArray();
+```
+
+To form a query with query inside is very easy, just add a query in `ConstantScoreQuery` constructor instead of filter.
+
+```JSON
+{
+    "constant_score" : {
+        "query" : {
+            "term" : { "user" : "kimchy"}
+        },
+        "boost" : 1.2
+    }
+}
+```
+
+via DSL:
+
+```php
+$termQuery = new TermQuery("user", "kimchy");
+$constantScoreQuery = new ConstantScoreQuery($termQuery, ["boost" => 1.2]);
+
+$search = new Search();
+$search->addQuery($constantScoreQuery);
+
+$queryArray = $search->toArray();
+```
+
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-constant-score-query.html
diff --git a/docs/Query/DisMax.md b/docs/Query/DisMax.md
new file mode 100644
index 0000000000000000000000000000000000000000..2a1a4490f83678795f11c932c7c9b42c5273c5e0
--- /dev/null
+++ b/docs/Query/DisMax.md
@@ -0,0 +1,61 @@
+# Dis Max query
+
+> More info about Dis Max query is in the [official elasticsearch docs][1]
+
+A query that generates the union of documents produced by its subqueries, and that scores each document with the
+maximum score for that document as produced by any subquery, plus a tie breaking increment for any additional matching
+subqueries.
+
+Lets try to write this example
+```JSON
+{
+    "dis_max" : {
+        "tie_breaker" : 0.7,
+        "boost" : 1.2,
+        "queries" : [
+            {
+                "term" : { "age" : 34 }
+            },
+            {
+                "term" : { "age" : 35 }
+            }
+        ]
+    }
+}
+```
+
+In DSL :
+
+```php
+$termQuery1 = new TermQuery('age', 34);
+$termQuery2 = new TermQuery('age', 35);
+
+$disMaxQuery = new DisMaxQuery();
+$disMaxQuery->addParameter('tie_breaker', 0.7);
+$disMaxQuery->addParameter('boost', 1.2);
+$disMaxQuery->addQuery($termQuery1);
+$disMaxQuery->addQuery($termQuery2);
+
+$search = new Search();
+$search->addQuery($disMaxQuery);
+
+$queryArray = $search->toArray();
+```
+
+Parameters can be set in constructor thus shorter version of DisMaxQuery is possible:
+
+```php
+$termQuery1 = new TermQuery('age', 34);
+$termQuery2 = new TermQuery('age', 35);
+
+$disMaxQuery = new DisMaxQuery(['tie_breaker' => 0.7, 'boost' => 1.2]);
+$disMaxQuery->addQuery($termQuery1);
+$disMaxQuery->addQuery($termQuery2);
+
+$search = new Search();
+$search->addQuery($disMaxQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-dis-max-query.html
diff --git a/docs/Query/Filtered.md b/docs/Query/Filtered.md
new file mode 100644
index 0000000000000000000000000000000000000000..dd88dc654523cf06ebf9712f3e7bc3f53757966c
--- /dev/null
+++ b/docs/Query/Filtered.md
@@ -0,0 +1,58 @@
+# Filtered query
+
+> More info about filtered query is in the [official elasticsearch docs][1]
+
+The filtered query is used to combine another query with any filter. Filters are usually faster than queries.
+
+Lets try to write this example
+```JSON
+{
+    "filtered": {
+        "query": {
+            "match": { "tweet": "full text search" }
+        },
+        "filter": {
+            "range": { "created": { "gte": "now - 1d / d" }}
+        }
+    }
+}
+```
+
+In DSL:
+
+```php
+$matchQuery = new MatchQuery('tweet', 'full text search');
+$rangeFilter = new RangeFilter('created', ['gte' => 'now - 1d / d']);
+
+$filteredQuery = new FilteredQuery($matchQuery, $rangeFilter);
+
+$search = new Search();
+$search->addQuery($filteredQuery);
+
+$queryArray = $search->toArray();
+```
+
+Or:
+
+```php
+$matchQuery = new MatchQuery('tweet', 'full text search');
+$rangeFilter = new RangeFilter('created', ['gte' => 'now - 1d / d']);
+
+$filteredQuery = new FilteredQuery();
+$filteredQuery->setQuery($matchQuery);
+$filteredQuery->setFilter($rangeFilter);
+
+$search = new Search();
+$search->addQuery($filteredQuery);
+
+$queryArray = $search->toArray();
+```
+
+Multiple queries and filters can be used with help off [Bool Query][2] and [Bool Filter][3] respectively.
+
+If query is not set it defaults to Match all, thus Filtered query can be used as filter in places where query is
+expected.
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-filtered-query.html
+[2]: Bool.md
+[3]: ../Filter/Bool.md
diff --git a/docs/Query/FunctionScore.md b/docs/Query/FunctionScore.md
new file mode 100644
index 0000000000000000000000000000000000000000..219ccf963ea4b776ba92133cb594b1d5367c899b
--- /dev/null
+++ b/docs/Query/FunctionScore.md
@@ -0,0 +1,175 @@
+# Function Score Query
+
+> More info about function score query is in the [official elasticsearch docs][1]
+
+The function score query allows you to modify the score of documents that are retrieved by a query. This can be useful
+if, for example, a score function is computationally expensive and it is sufficient to compute the score on a filtered
+set of documents.
+
+## Example with linear decay function
+```JSON
+{
+  "query": {
+    "function_score": {
+      "query": {
+        "range": {
+          "price": {
+            "gte": 10,
+            "lte": 100
+          }
+        }
+      },
+      "functions": [
+        {
+          "linear": {
+            "price": {
+              "origin": 10,
+              "scale": 50,
+              "offset": 0,
+              "decay" : 0.5
+            }
+          }
+        }
+      ]
+    }
+  }
+}
+```
+
+In DSL
+
+```php
+$rangeQuery = new RangeQuery('price');
+$rangeQuery->addParameter(RangeQuery::GTE, 10);
+$rangeQuery->addParameter(RangeQuery::LTE, 100);
+$functionScoreQuery = new FunctionScoreQuery($rangeQuery);
+$functionScoreQuery->addDecayFunction(
+    'linear',
+    'price',
+    [
+        'origin' => 10,
+        'scale' => 50,
+        'offset' => 0,
+        'decay' => 0.5
+    ]
+);
+
+$search = new Search();
+$search->addQuery($functionScoreQuery);
+
+$queryArray = $search->toArray();
+```
+
+## Example weight function to multiply score of subset
+
+```JSON
+{
+  "query": {
+    "function_score": {
+      "query": {
+        "match_all": {}
+      },
+      "functions": [
+        {
+          "weight": 2,
+          "filter": {
+            "range": {
+              "price": {
+                "gte": 10,
+                "lte": 40
+              }
+            }
+          }
+        }
+      ]
+    }
+  }
+}
+```
+
+In DSL:
+
+```php
+$functionScoreQuery = new FunctionScoreQuery(new MatchAllQuery());
+$rangeFilter = new RangeFilter('price', ['gte' => 10, 'lte' => 100]);
+$functionScoreQuery->addWeightFunction(2, $rangeFilter);
+
+$search = new Search();
+$search->addQuery($functionScoreQuery);
+
+$queryArray = $search->toArray();
+```
+
+## Example Field Value Factor Function
+
+```php
+$functionScoreQuery = new FunctionScoreQuery(new MatchAllQuery());
+$existsFilter = new ExistsFilter('price');
+$functionScoreQuery->addFieldValueFactorFunction('price', 0.5, 'ln', $existsFilter);
+
+$search = new Search();
+$search->addQuery($functionScoreQuery);
+
+$queryArray = $search->toArray();
+```
+
+Will result in 
+
+```JSON
+{
+  "query": {
+    "function_score": {
+      "query": {
+        "match_all": {}
+      },
+      "functions": [
+        {
+          "field_value_factor": {
+            "field": "price",
+            "factor": 0.5,
+            "modifier": "ln"
+          },
+          "filter": {
+            "exists": {
+              "field": "price"
+            }
+          }
+        }
+      ]
+    }
+  }
+}
+```
+
+## Random function example
+
+```php
+$functionScoreQuery = new FunctionScoreQuery(new MatchAllQuery());
+$functionScoreQuery->addRandomFunction();
+
+$search = new Search();
+$search->addQuery($functionScoreQuery);
+
+$queryArray = $search->toArray();
+```
+
+Will result in
+
+```JSON
+{
+  "query": {
+    "function_score": {
+      "query": {
+        "match_all": {}
+      },
+      "functions": [
+        {
+          "random_score": {}
+        }
+      ]
+    }
+  }
+}
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html
diff --git a/docs/Query/Fuzzy.md b/docs/Query/Fuzzy.md
new file mode 100644
index 0000000000000000000000000000000000000000..2f3ed8a7aaf311ce60067536c25e9a97d1041106
--- /dev/null
+++ b/docs/Query/Fuzzy.md
@@ -0,0 +1,63 @@
+# Fuzzy Query
+
+> More info about fuzzy query is in the [official elasticsearch docs][1]
+
+The fuzzy query uses similarity based on Levenshtein edit distance for string fields, and a +/- margin on numeric and
+date fields.
+
+## Simple example
+
+```JSON
+{
+    "fuzzy" : { "user" : "ki" }
+}
+```
+
+In DSL:
+
+```php
+$fuzzyQuery = new FuzzyQuery('user', 'ki');
+
+$search = new Search();
+$search->addQuery($fuzzyQuery);
+
+$queryArray = $search->toArray();
+```
+
+## With more advanced settings
+
+```JSON
+{
+    "fuzzy" : {
+        "user" : {
+            "value" :         "ki",
+            "boost" :         1.0,
+            "fuzziness" :     2,
+            "prefix_length" : 0,
+            "max_expansions": 100
+        }
+    }
+}
+```
+
+In DSL
+```php
+$fuzzyQuery = new FuzzyQuery(
+    'user',
+    'ki',
+    [
+        'boost' => 1,
+        'fuzziness' => 2,
+        'prefix_length' => 0,
+        'max_expansions' => 100,
+    ]
+);
+
+
+$search = new Search();
+$search->addQuery($fuzzyQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-fuzzy-query.html
diff --git a/docs/Query/FuzzyLikeThisField.md b/docs/Query/FuzzyLikeThisField.md
new file mode 100644
index 0000000000000000000000000000000000000000..eecb6a47356454490ac090a26c3e0af8a213d803
--- /dev/null
+++ b/docs/Query/FuzzyLikeThisField.md
@@ -0,0 +1,38 @@
+# Fuzzy Like This Field Query
+
+> More info about fuzzy like this field query is in the [official elasticsearch docs][1]
+
+The fuzzy like this field query is the same as the [fuzzy like this query][2], except that it runs against a single
+field. It provides nicer query DSL over the generic fuzzy like this query, and support typed fields query
+(automatically wraps typed fields with type filter to match only on the specific type).
+
+## Simple example
+
+```JSON
+{
+    "fuzzy_like_this_field" : {
+        "name.first" : {
+            "like_text" : "text like this one",
+            "max_query_terms" : 12
+        }
+    }
+}
+```
+
+In DSL:
+
+```php
+$fuzzyLikeThisFieldQuery = new FuzzyLikeThisFieldQuery(
+    'name.first',
+    'text like this one',
+    [ 'max_query_terms' => 12 ]
+);
+
+$search = new Search();
+$search->addQuery($fuzzyLikeThisFieldQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-flt-field-query.html
+[2]: FuzzyLikeThisQuery.md
diff --git a/docs/Query/FuzzyLikeThisQuery.md b/docs/Query/FuzzyLikeThisQuery.md
new file mode 100644
index 0000000000000000000000000000000000000000..de05d402fc240fac5bca315f9d92008d231b2e94
--- /dev/null
+++ b/docs/Query/FuzzyLikeThisQuery.md
@@ -0,0 +1,34 @@
+# Fuzzy Like This Query
+
+> More info about fuzzy like this field query is in the [official elasticsearch docs][1]
+
+Fuzzy like this query find documents that are "like" provided text by running it against one or more fields.
+
+## Simple example
+
+```JSON
+{
+    "fuzzy_like_this" : {
+        "fields" : ["name.first", "name.last"],
+        "like_text" : "text like this one",
+        "max_query_terms" : 12
+    }
+}
+```
+
+In DSL:
+
+```php
+$fuzzyLikeThisQuery = new FuzzyLikeThisQuery(
+    ['name.first', 'name.last'],
+    'text like this one',
+    [ 'max_query_terms' => 12 ]
+);
+
+$search = new Search();
+$search->addQuery($fuzzyLikeThisQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-flt-query.html
diff --git a/docs/Query/HasChild.md b/docs/Query/HasChild.md
new file mode 100644
index 0000000000000000000000000000000000000000..7124bf37336c548db93c3f9bf521de632c033de7
--- /dev/null
+++ b/docs/Query/HasChild.md
@@ -0,0 +1,36 @@
+# Has child Query
+
+> More info about has child query is in the [official elasticsearch docs][1]
+
+The has child query accepts a query and the child type to run against, and results in parent documents that have child
+docs matching the query.
+
+## Simple example
+
+```JSON
+{
+    "has_child" : {
+        "type" : "blog_tag",
+        "query" : {
+            "term" : {
+                "tag" : "something"
+            }
+        }
+    }
+}
+```
+
+In DSL:
+
+```php
+$termQuery = new TermQuery('tag', 'something');
+
+$hasChildQuery = new HasChildQuery('blog_tag', $termQuery);
+
+$search = new Search();
+$search->addQuery($hasChildQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-child-query.html
diff --git a/docs/Query/HasParent.md b/docs/Query/HasParent.md
new file mode 100644
index 0000000000000000000000000000000000000000..a6a12db9b4030c156f00bfeb47f00102a8e1f191
--- /dev/null
+++ b/docs/Query/HasParent.md
@@ -0,0 +1,36 @@
+# Has Parent Query
+
+> More info about has parent query is in the [official elasticsearch docs][1]
+
+The has parent query accepts a query and a parent type. The query is executed in the parent document space, which is
+specified by the parent type. This filter returns child documents which associated parents have matched.
+
+## Simple example
+
+```JSON
+{
+    "has_parent" : {
+        "parent_type" : "blog",
+        "query" : {
+            "term" : {
+                "tag" : "something"
+            }
+        }
+    }
+}
+```
+
+In DSL:
+
+```php
+$termQuery = new TermQuery('tag', 'something');
+
+$hasParentQuery = new HasParentQuery('blog', $termQuery);
+
+$search = new Search();
+$search->addQuery($hasParentQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-parent-query.html
diff --git a/docs/Query/Ids.md b/docs/Query/Ids.md
new file mode 100644
index 0000000000000000000000000000000000000000..bd22eadae80e19b1ac708aedc4ee4824f7a94f92
--- /dev/null
+++ b/docs/Query/Ids.md
@@ -0,0 +1,29 @@
+# Ids Query
+
+> More info about ids query is in the [official elasticsearch docs][1]
+
+Filters documents that only have the provided ids.
+
+## Simple example
+
+```JSON
+{
+    "ids" : {
+        "type" : "my_type",
+        "values" : ["1", "4", "100"]
+    }
+}
+```
+
+In DSL:
+
+```php
+$idsQuery = new IdsQuery(['1', '4', '100'], ['type' => 'my_type']);
+
+$search = new Search();
+$search->addQuery($idsQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-ids-query.html
diff --git a/docs/Query/Indices.md b/docs/Query/Indices.md
new file mode 100644
index 0000000000000000000000000000000000000000..f02c0010e8f01f3512094255304826fcf2613aac
--- /dev/null
+++ b/docs/Query/Indices.md
@@ -0,0 +1,39 @@
+# Indices Query
+
+> More info about indices query is in the [official elasticsearch docs][1]
+
+The indices query can be used when executed across multiple indices, allowing to have a query that executes
+only when executed on an index that matches a specific list of indices, and another query that executes
+when it is executed on an index that does not match the listed indices.
+
+## Simple example
+
+```JSON
+{
+    "indices" : {
+        "indices" : ["index1", "index2"],
+        "query" : {
+            "term" : { "tag" : "wow" }
+        },
+        "no_match_query" : {
+            "term" : { "tag" : "kow" }
+        }
+    }
+}
+```
+
+In DSL:
+
+```php
+$matchTermQuery = new TermQuery('tag', 'wow');
+$noMatchTermQuery = new TermQuery('tag', 'kow');
+
+$indicesQuery = new IndicesQuery(['index1', 'index2'], $matchTermQuery, $noMatchTermQuery);
+
+$search = new Search();
+$search->addQuery($indicesQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-indices-query.html
diff --git a/docs/Query/Match.md b/docs/Query/Match.md
new file mode 100644
index 0000000000000000000000000000000000000000..ec523de1bd26142c7b594ec565f0e1fbb0323823
--- /dev/null
+++ b/docs/Query/Match.md
@@ -0,0 +1,28 @@
+# Match Query
+
+> More info about match query is in the [official elasticsearch docs][1]
+
+A family of match queries that accept text/numerics/dates, analyzes it, and constructs a query out of it.
+
+## Simple example
+
+```JSON
+{
+    "match" : {
+        "message" : "this is a test"
+    }
+}
+```
+
+In DSL:
+
+```php
+$matchQuery = new MatchQuery('message', 'this is a test');
+
+$search = new Search();
+$search->addQuery($matchQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html
diff --git a/docs/Query/MatchAll.md b/docs/Query/MatchAll.md
new file mode 100644
index 0000000000000000000000000000000000000000..b07cfae78bf4988e6d196c5ad54852ef246f469d
--- /dev/null
+++ b/docs/Query/MatchAll.md
@@ -0,0 +1,26 @@
+# Match All Query
+
+> More info about match all query is in the [official elasticsearch docs][1]
+
+A query that matches all documents
+
+## Simple example
+
+```JSON
+{
+    "match_all" : { }
+}
+```
+
+In DSL:
+
+```php
+$matchAllQuery = new MatchAllQuery();
+
+$search = new Search();
+$search->addQuery($matchAllQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-query.html
diff --git a/docs/Query/MoreLikeThis.md b/docs/Query/MoreLikeThis.md
new file mode 100644
index 0000000000000000000000000000000000000000..7777e31659c36c7a7969bd006a1f0ab417754a6d
--- /dev/null
+++ b/docs/Query/MoreLikeThis.md
@@ -0,0 +1,38 @@
+# More Like This Query
+
+> More info about more like this query is in the [official elasticsearch docs][1]
+
+The More Like This Query (MLT Query) finds documents that are "like" a given set of documents.
+
+## Simple example
+
+```JSON
+{
+    "more_like_this" : {
+        "fields" : ["title", "description"],
+        "like_text" : "Once upon a time",
+        "min_term_freq" : 1,
+        "max_query_terms" : 12
+    }
+}
+```
+
+In DSL:
+
+```php
+$moreLikeThisQuery = new MoreLikeThisQuery(
+    'Once upon a time',
+    [
+        'fields' => ['title', 'description'],
+        'min_term_freq' => 1,
+        'max_query_terms' => 12,
+    ]
+);
+
+$search = new Search();
+$search->addQuery($moreLikeThisQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-mlt-query.html
diff --git a/docs/Query/MultiMatch.md b/docs/Query/MultiMatch.md
new file mode 100644
index 0000000000000000000000000000000000000000..c9905ec5be91b62998353ea7adea4ec9720979ca
--- /dev/null
+++ b/docs/Query/MultiMatch.md
@@ -0,0 +1,33 @@
+# Multi Match Query
+
+> More info about multi match query is in the [official elasticsearch docs][1]
+
+The multi match query builds on the [match][2] query to allow multi-field queries:
+
+## Simple example
+
+```JSON
+{
+  "multi_match" : {
+    "query":    "this is a test", 
+    "fields": [ "subject", "message" ] 
+  }
+}
+```
+
+In DSL:
+
+```php
+$multiMatchQuery = new MultiMatchQuery(
+    ['subject', 'message'],
+    'this is a test'
+);
+
+$search = new Search();
+$search->addQuery($multiMatchQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html
+[2]: Match.md
diff --git a/docs/Query/Nested.md b/docs/Query/Nested.md
new file mode 100644
index 0000000000000000000000000000000000000000..4830f6b48c280b3f59b7002f467a7417d25addad
--- /dev/null
+++ b/docs/Query/Nested.md
@@ -0,0 +1,54 @@
+# Nested Query
+
+> More info about nested query is in the [official elasticsearch docs][1]
+
+Nested query allows to query nested objects / documents (see [nested mapping][2]). The query is executed against the nested
+objects / documents as if they were indexed as separate documents (they are, internally) and resulting in the root
+parent document (or parent nested mapping).
+
+## Simple example
+
+```JSON
+{
+    "nested" : {
+        "path" : "obj1",
+        "score_mode" : "avg",
+        "query" : {
+            "bool" : {
+                "must" : [
+                    {
+                        "match" : {"obj1.name" : "blue"}
+                    },
+                    {
+                        "range" : {"obj1.count" : {"gt" : 5}}
+                    }
+                ]
+            }
+        }
+    }
+}
+```
+
+In DSL:
+
+```php
+$matchQuery = new MatchQuery('obj1.name', 'blue');
+$rangeQuery = new RangeQuery('obj1.count', ['gt' => 5]);
+$boolQuery = new BoolQuery();
+$boolQuery->add($matchQuery);
+$boolQuery->add($rangeQuery);
+
+$nestedQuery = new NestedQuery(
+    'obj1',
+    $boolQuery
+);
+$nestedQuery->addParameter('score_mode', 'avg');
+
+$search = new Search();
+$search->addQuery($nestedQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-query.html
+[2]: https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-nested-type.html
diff --git a/docs/Query/Prefix.md b/docs/Query/Prefix.md
new file mode 100644
index 0000000000000000000000000000000000000000..32cda5971f31a33722dabad25e9bc3a20875b302
--- /dev/null
+++ b/docs/Query/Prefix.md
@@ -0,0 +1,26 @@
+# Prefix Query
+
+> More info about prefix query is in the [official elasticsearch docs][1]
+
+Matches documents that have fields containing terms with a specified prefix.
+
+## Simple example
+
+```JSON
+{
+    "prefix" : { "user" : "ki" }
+}
+```
+
+In DSL:
+
+```php
+$prefixQuery = new PrefixQuery('user', 'ki');
+
+$search = new Search();
+$search->addQuery($prefixQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-query.html
diff --git a/docs/Query/QueryString.md b/docs/Query/QueryString.md
new file mode 100644
index 0000000000000000000000000000000000000000..79f4538dfc348e7d18aa50328b43dcc752272fc6
--- /dev/null
+++ b/docs/Query/QueryString.md
@@ -0,0 +1,30 @@
+# Query String Query
+
+> More info about query string query is in the [official elasticsearch docs][1]
+
+A query that uses a query parser in order to parse its content.
+
+## Simple example
+
+```JSON
+{
+    "query_string" : {
+        "default_field" : "content",
+        "query" : "this AND that OR thus"
+    }
+}
+```
+
+In DSL:
+
+```php
+$queryStringQuery = new QueryStringQuery('this AND that OR thus');
+$queryStringQuery->addParameter('default_field', 'content');
+
+$search = new Search();
+$search->addQuery($queryStringQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html
diff --git a/docs/Query/Range.md b/docs/Query/Range.md
new file mode 100644
index 0000000000000000000000000000000000000000..3e90f0b6143684fbae9b44cef31095b58ab13b45
--- /dev/null
+++ b/docs/Query/Range.md
@@ -0,0 +1,41 @@
+# Range Query
+
+> More info about range query is in the [official elasticsearch docs][1]
+
+Matches documents with fields that have terms within a certain range.
+
+## Simple example
+
+```JSON
+{
+    {
+        "range" : {
+            "age" : {
+                "gte" : 10,
+                "lte" : 20,
+                "boost" : 2.0
+            }
+        }
+    }
+}
+```
+
+In DSL:
+
+```php
+$rangeQuery = new RangeQuery(
+    'age',
+    [
+        'gte' => 10,
+        'lte' => 20,
+        'boost' => 2.0,
+    ]
+);
+
+$search = new Search();
+$search->addQuery($rangeQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html
diff --git a/docs/Query/Regexp.md b/docs/Query/Regexp.md
new file mode 100644
index 0000000000000000000000000000000000000000..d698b004f93bb70aa8c60c7860bc8f1f346aa938
--- /dev/null
+++ b/docs/Query/Regexp.md
@@ -0,0 +1,30 @@
+# Regexp Query
+
+> More info about regexp query is in the [official elasticsearch docs][1]
+
+The regexp query allows you to use regular expression term queries.
+
+## Simple example
+
+```JSON
+{
+    "filter": {
+        "regexp":{
+            "name.first" : "s.*y"
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$regexpQuery = new RegexpQuery('name.first', 's.*y');
+
+$search = new Search();
+$search->addQuery($regexpQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html
diff --git a/docs/Query/SimpleQueryString.md b/docs/Query/SimpleQueryString.md
new file mode 100644
index 0000000000000000000000000000000000000000..8f21ded57f9f5534ecab2db2bb5707f7dc5c1b7b
--- /dev/null
+++ b/docs/Query/SimpleQueryString.md
@@ -0,0 +1,38 @@
+# Simple Query String Query
+
+> More info about simple query string query is in the [official elasticsearch docs][1]
+
+A query that uses the SimpleQueryParser to parse its context
+
+## Simple example
+
+```JSON
+{
+    "simple_query_string" : {
+        "query": "\"fried eggs\" +(eggplant | potato) -frittata",
+        "analyzer": "snowball",
+        "fields": ["body^5","_all"],
+        "default_operator": "and"
+    }
+}
+```
+
+In DSL:
+
+```php
+$simpleQueryStringQuery = new SimpleQueryStringQuery(
+    '"fried eggs" +(eggplant | potato) -frittata',
+    [
+        'analyzer' => 'snowball',
+        'fields' => ['body^5', '_all'],
+        'default_operator' => 'and',
+    ]
+);
+
+$search = new Search();
+$search->addQuery($simpleQueryStringQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html
diff --git a/docs/Query/Term.md b/docs/Query/Term.md
new file mode 100644
index 0000000000000000000000000000000000000000..a71ceb1c2232a00de27ed7110d94bc1325ea3d26
--- /dev/null
+++ b/docs/Query/Term.md
@@ -0,0 +1,27 @@
+# Term Query
+
+> More info about term query is in the [official elasticsearch docs][1]
+
+The term query finds documents that contain the exact term specified in the inverted index.
+
+
+## Simple example
+
+```JSON
+{
+    "term" : { "user" : "Kimchy" } 
+}
+```
+
+In DSL:
+
+```php
+$termQuery = new TermQuery('user', 'Kimchy');
+
+$search = new Search();
+$search->addQuery($termQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html
diff --git a/docs/Query/Terms.md b/docs/Query/Terms.md
new file mode 100644
index 0000000000000000000000000000000000000000..e38e6ac6c0be5be7851a7da5a585e22dd2a531d2
--- /dev/null
+++ b/docs/Query/Terms.md
@@ -0,0 +1,33 @@
+# Terms Query
+
+> More info about terms query is in the [official elasticsearch docs][1]
+
+A query that match on any of the provided terms.
+
+## Simple example
+
+```JSON
+{
+    "terms" : {
+        "tags" : [ "blue", "pill" ],
+        "minimum_should_match" : 1
+    }
+}
+```
+
+In DSL:
+
+```php
+$termsQuery = new TermsQuery(
+    'tags',
+    ['blue', 'pill'],
+    ['minimum_should_match' => 1]
+);
+
+$search = new Search();
+$search->addQuery($termsQuery);
+
+$queryArray = $search->toArray();
+```
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html
diff --git a/docs/Query/Wildcard.md b/docs/Query/Wildcard.md
new file mode 100644
index 0000000000000000000000000000000000000000..4c646c5e9ff31628befcf5bb5cd1cd3baec36e93
--- /dev/null
+++ b/docs/Query/Wildcard.md
@@ -0,0 +1 @@
+# Wildcard Query
\ No newline at end of file
diff --git a/docs/Query/index.md b/docs/Query/index.md
new file mode 100644
index 0000000000000000000000000000000000000000..3345e50c9c9397e9bb3297671b3997dda2fc94bb
--- /dev/null
+++ b/docs/Query/index.md
@@ -0,0 +1,58 @@
+# Query
+
+Objective query builder represents all available [Elasticsearch queries][1].
+
+To form a query you have to create `Search` object. See below an example of match all query usage.
+
+```php
+$search = new Search();
+$matchAllQuery = new MatchAllQuery();
+$search->addQuery($matchAllQuery);
+$queryArray = $search->toArray();
+```
+
+Query handles are necessary little things like where to put `\stdClass` and where to simple array. So by using DSL builder you can be always sure that it will form a correct query.
+
+Here's `$queryArray` var_dump:
+
+```php
+//$queryArray content
+'query' =>
+    [
+      'match_all' => \stdClass(),
+    ]
+```
+
+For more information how to combine search queries take a look at [How to search](../HowTo/HowToSearch.md) chapter.
+
+
+## Queries:
+ - [Bool](Bool.md)
+ - [Boosting](Boosting.md)
+ - [Common terms](CommonTerms.md)
+ - [Constant Score](ConstantScore.md)
+ - [DisMax](DisMax.md)
+ - [Filtered](Filtered.md)
+ - [Function score](FunctionScore.md)
+ - [Fuzzy](Fuzzy.md)
+ - [Fuzzy like this field](FuzzyLikeThisField.md)
+ - [Fuzzy like this query](FuzzyLikeThisQuery.md)
+ - [Has child](HasChild.md)
+ - [Has parent](HasParent.md)
+ - [Ids](Ids.md)
+ - [Indices](Indices.md)
+ - [Match all](MatchAll.md)
+ - [Match](Match.md)
+ - [More like this](MoreLikeThis.md)
+ - [Multi match](MultiMatch.md)
+ - [Nested](Nested.md)
+ - [Prefix](Prefix.md)
+ - [Query string](QueryString.md)
+ - [Range](Range.md)
+ - [Regexp](Regexp.md)
+ - [Simple query string](SimpleQueryString.md)
+ - [Term](Term.md)
+ - [Terms](Terms.md)
+ - [Wildcard](Wildcard.md)
+
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-queries.html
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000000000000000000000000000000000000..4ab5421dae8d7da2157a6a173563a60078ba6e7f
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,16 @@
+# Elasticsearch DSL
+
+Welcome to Elasticsearch DSL library. The main purpose of this library is to provide objective query builder for [elasticsearch-php][1] client.
+
+Everything starts from the `Search` object. We recommend first to take a look at the [Search](HowTo/HowToSearch.md) chapter.
+
+### Topics:
+- [Build Queries](Query/index.md)
+- [Build Filters](Filter/index.md)
+- [Build Aggregations](Aggregation/index.md)
+
+### How to
+- [How to combine `Filter` and `Query`]
+- [How to add sorting]
+
+[1]: https://github.com/elastic/elasticsearch-php
diff --git a/src/Aggregation/TopHitsAggregation.php b/src/Aggregation/TopHitsAggregation.php
index 03f525d63dc16a1db720a19e3c5f6a49e6c4fc8f..0212be360f0d7f693a3b93c71726a44ccf83d738 100644
--- a/src/Aggregation/TopHitsAggregation.php
+++ b/src/Aggregation/TopHitsAggregation.php
@@ -153,6 +153,6 @@ class TopHitsAggregation extends AbstractAggregation
             }
         );
 
-        return $fd;
+        return $this->processArray($fd);
     }
 }
diff --git a/src/FilterOrQueryDetectionTrait.php b/src/FilterOrQueryDetectionTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..ae6e394541d5d61747087ca423e65581e5dddd13
--- /dev/null
+++ b/src/FilterOrQueryDetectionTrait.php
@@ -0,0 +1,43 @@
+<?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;
+
+/**
+ * A trait which can detect query or filter is passed.
+ */
+trait FilterOrQueryDetectionTrait
+{
+    /**
+     * Detects a dsl type.
+     *
+     * @param BuilderInterface $object
+     * @return string
+     *
+     * @throws \InvalidArgumentException
+     */
+    public function detectDslType(BuilderInterface $object)
+    {
+        $namespace = get_class($object);
+
+        $dslTypes = ['Filter', 'Query'];
+
+        foreach ($dslTypes as $type) {
+            $length = strlen($type);
+            $dslType = substr($namespace, -$length);
+            if ($dslType === $type) {
+                return strtolower($dslType);
+            }
+        }
+
+        throw new \InvalidArgumentException();
+    }
+}
diff --git a/src/Query/ConstantScoreQuery.php b/src/Query/ConstantScoreQuery.php
index 6c3b6bbbf91750692552d9c4efd001412c741d89..d4662d25099fd32be477c22be3637d3be7935637 100644
--- a/src/Query/ConstantScoreQuery.php
+++ b/src/Query/ConstantScoreQuery.php
@@ -12,7 +12,7 @@
 namespace ONGR\ElasticsearchDSL\Query;
 
 use ONGR\ElasticsearchDSL\BuilderInterface;
-use ONGR\ElasticsearchDSL\DslTypeAwareTrait;
+use ONGR\ElasticsearchDSL\FilterOrQueryDetectionTrait;
 use ONGR\ElasticsearchDSL\ParametersTrait;
 
 /**
@@ -21,7 +21,7 @@ use ONGR\ElasticsearchDSL\ParametersTrait;
 class ConstantScoreQuery implements BuilderInterface
 {
     use ParametersTrait;
-    use DslTypeAwareTrait;
+    use FilterOrQueryDetectionTrait;
 
     /**
      * @var BuilderInterface
@@ -36,7 +36,6 @@ class ConstantScoreQuery implements BuilderInterface
     {
         $this->query = $query;
         $this->setParameters($parameters);
-        $this->setDslType('query');
     }
 
     /**
@@ -53,7 +52,7 @@ class ConstantScoreQuery implements BuilderInterface
     public function toArray()
     {
         $query = [
-            strtolower($this->getDslType()) => [
+            $this->detectDslType($this->query) => [
                 $this->query->getType() => $this->query->toArray(),
             ],
         ];
diff --git a/src/Query/FuzzyLikeThisQuery.php b/src/Query/FuzzyLikeThisQuery.php
index c19c36be0858aa789d646b45f72b5d70f14ecb55..af2ff21c6a910bcb0c36bbe76f3d1c8e6f6ba6e9 100644
--- a/src/Query/FuzzyLikeThisQuery.php
+++ b/src/Query/FuzzyLikeThisQuery.php
@@ -32,12 +32,16 @@ class FuzzyLikeThisQuery implements BuilderInterface
     private $likeText;
 
     /**
-     * @param string[] $fields
-     * @param string   $likeText
-     * @param array    $parameters
+     * @param string|string[] $fields
+     * @param string          $likeText
+     * @param array           $parameters
      */
-    public function __construct(array $fields, $likeText, array $parameters = [])
+    public function __construct($fields, $likeText, array $parameters = [])
     {
+        if (!is_array($fields)) {
+            $fields = [$fields];
+        }
+
         $this->fields = $fields;
         $this->likeText = $likeText;
         $this->setParameters($parameters);
diff --git a/tests/Aggregation/TopHitsAggregationTest.php b/tests/Aggregation/TopHitsAggregationTest.php
index cd63b502d2b0932580cc935b5e917ce02cb467e9..fa2e91ff9e3bd4416d4e838e2d8ecfb08520889a 100644
--- a/tests/Aggregation/TopHitsAggregationTest.php
+++ b/tests/Aggregation/TopHitsAggregationTest.php
@@ -40,4 +40,23 @@ class TopHitsAggregationTest extends \PHPUnit_Framework_TestCase
 
         $this->assertEquals($expected, $aggregation->toArray());
     }
+
+    /**
+     * Tests if adding parameters has any effect.
+     */
+    public function testParameters()
+    {
+        $topHitsAggregation = new TopHitsAggregation('test');
+        $topHitsAggregation->addParameter('_source', ['include' => ['title']]);
+        $expectedAgg = new \stdClass();
+        $expectedAgg->sort = [];
+        $expectedAgg->_source = ['include' => ['title']];
+        $expected = [
+            'agg_test' => [
+                'top_hits' => $expectedAgg,
+            ],
+        ];
+
+        $this->assertEquals($expected, $topHitsAggregation->toArray());
+    }
 }
diff --git a/tests/FilterOrQueryDetectionTraitTest.php b/tests/FilterOrQueryDetectionTraitTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9493dcf02176cf388134b2944d635338e0a27500
--- /dev/null
+++ b/tests/FilterOrQueryDetectionTraitTest.php
@@ -0,0 +1,69 @@
+<?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\Tests\Unit\DSL;
+
+use ONGR\ElasticsearchDSL\Aggregation\GlobalAggregation;
+use ONGR\ElasticsearchDSL\Filter\MatchAllFilter;
+use ONGR\ElasticsearchDSL\FilterOrQueryDetectionTrait;
+use ONGR\ElasticsearchDSL\Query\MatchAllQuery;
+
+/**
+ * Test for FilterOrQueryDetectionTrait.
+ */
+class FilterOrQueryDetectionTraitTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var FilterOrQueryDetectionTrait
+     */
+    private $mock;
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setUp()
+    {
+        $this->mock = $this->getMockForTrait('ONGR\ElasticsearchDSL\FilterOrQueryDetectionTrait');
+    }
+
+    /**
+     * Tests if setDslType throws exception.
+     *
+     * @expectedException \InvalidArgumentException
+     */
+    public function testIfTraitDetectsNotKnowType()
+    {
+        $aggregation = new GlobalAggregation('global');
+        $this->mock->detectDslType($aggregation);
+    }
+
+    /**
+     * Tests if detectDslType detects passed query.
+     */
+    public function testIfTraitDetectsQuery()
+    {
+        $query = new MatchAllQuery();
+        $result = $this->mock->detectDslType($query);
+
+        $this->assertEquals('query', $result);
+    }
+
+    /**
+     * Tests if detectDslType detects passed filter.
+     */
+    public function testIfTraitDetectsFilter()
+    {
+        $filter = new MatchAllFilter();
+        $result = $this->mock->detectDslType($filter);
+
+        $this->assertEquals('filter', $result);
+    }
+}
diff --git a/tests/Query/FuzzyLikeThisQueryTest.php b/tests/Query/FuzzyLikeThisQueryTest.php
index 32e193ab968b441c2ab4c1fa55b89ee6fd0cbefb..3563b6455f9fee75c1e1a16398b40ce3eef6b583 100644
--- a/tests/Query/FuzzyLikeThisQueryTest.php
+++ b/tests/Query/FuzzyLikeThisQueryTest.php
@@ -52,4 +52,25 @@ class FuzzyLikeThisQueryTest extends \PHPUnit_Framework_TestCase
 
         $this->assertEquals('fuzzy_like_this', $fuzzyLikeThisQuery->getType());
     }
+
+    /**
+     * Tests if query accepts single field as string.
+     */
+    public function testSingleField()
+    {
+        $fuzzyLikeThisQuery = new FuzzyLikeThisQuery(
+            'name.first',
+            'text like this one',
+            [ 'max_query_terms' => 12 ]
+        );
+
+        $this->assertSame(
+            [
+                'fields' => ['name.first'],
+                'like_text' => 'text like this one',
+                'max_query_terms' => 12,
+            ],
+            $fuzzyLikeThisQuery->toArray()
+        );
+    }
 }