@@ -640,6 +640,163 @@ let filter = RegexpFilter (FieldName "user") (Regexp "bite.*app")
640640
641641#+END_SRC
642642
643+*** Aggregations
644+**** Adding aggregations to search
645+Aggregations can now be added to search queries, or made on their own.
646+#+BEGIN_SRC haskell
647+type Aggregations = M.Map Text Aggregation
648+data Aggregation
649+ = TermsAgg TermsAggregation
650+ | DateHistogramAgg DateHistogramAggregation
651+#+END_SRC
652+
653+For convenience, ```mkAggregations``` exists, that will create an
654+```Aggregations``` with the aggregation provided.
655+
656+For example:
657+#+BEGIN_SRC haskell
658+ let a = mkAggregations "users" $ TermsAgg $ mkTermsAggregation "user"
659+ let search = mkAggregateSearch Nothing a
660+#+END_SRC
661+
662+Aggregations can be added to an existing search, using the
663+```aggBody``` field
664+
665+#+BEGIN_SRC haskell
666+ let search = mkSearch (Just (MatchAllQuery Nothing)) Nothing
667+ let search' = search {aggBody = Just a}
668+#+END_SRC
669+
670+Since the ```Aggregations``` structure is just a Map Text
671+Aggregation, M.insert can be used to add additional aggregations.
672+
673+#+BEGIN_SRC haskell
674+ let a' = M.insert "age" (TermsAgg $ mkTermsAggregation "age") a
675+#+END_SRC
676+
677+**** Extracting aggregations from results
678+Aggregations are part of the reply structure of every search, in the
679+form of ~Maybe AggregationResults~
680+
681+#+BEGIN_SRC haskell
682+-- Lift decode and response body to be in the IO monad.
683+let decode' = liftM decode
684+let responseBody' = liftM responseBody
685+let reply = searchByIndex testServer testIndex search
686+let response = decode' $ responseBody' reply :: IO (Maybe (SearchResult Tweet))
687+
688+-- Now that we have our response, we can extract our terms aggregation result -- which is a list of buckets.
689+
690+let terms = do { response' <- response; return $ response' >>= aggregations >>= toTerms "users" }
691+terms
692+Just (Bucket {buckets = [TermsResult {termKey = "bitemyapp", termsDocCount = 1, termsAggs = Nothing}]})
693+#+END_SRC
694+
695+Note that bucket aggregation results, such as the TermsResult is a
696+member of the type class ~BucketAggregation~:
697+
698+#+BEGIN_SRC haskell
699+class BucketAggregation a where
700+ key :: a -> Text
701+ docCount :: a -> Int
702+ aggs :: a -> Maybe AggregationResults
703+#+END_SRC haskell
704+
705+You can use the ~aggs~ function to get any nested results, if
706+there were any. For example, if there were a nested terms
707+aggregation keyed to "age" in a TermsResult named ~termresult~, you would call ~aggs termresult >>=
708+toTerms "age"~
709+
710+**** Terms Aggregation
711+#+BEGIN_SRC haskell
712+data TermsAggregation
713+ = TermsAggregation {term :: Either Text Text,
714+ termInclude :: Maybe TermInclusion,
715+ termExclude :: Maybe TermInclusion,
716+ termOrder :: Maybe TermOrder,
717+ termMinDocCount :: Maybe Int,
718+ termSize :: Maybe Int,
719+ termShardSize :: Maybe Int,
720+ termCollectMode :: Maybe CollectionMode,
721+ termExecutionHint :: Maybe ExecutionHint,
722+ termAggs :: Maybe Aggregations}
723+#+END_SRC
724+
725+Term Aggregations have two factory functions,
726+~mkTermsAggregation~, and ~mkTermsScriptAggregation~, and can
727+be used as follows:
728+
729+#+BEGIN_SRC haskell
730+let ta = TermsAgg $ mkTermsAggregation "user"
731+#+END_SRC
732+
733+There are of course other options that can be added to a Terms
734+Aggregation, such as the collection mode:
735+#+BEGIN_SRC haskell
736+let ta = mkTermsAggregation "user"
737+let ta' = ta { termCollectMode = Just BreadthFirst }
738+let ta'' = TermsAgg ta'
739+#+END_SRC
740+
741+For more documentation on how the Terms Aggregation works, see
742+http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html
743+
744+**** Date Histogram Aggregation
745+
746+#+BEGIN_SRC haskell
747+data DateHistogramAggregation
748+ = DateHistogramAggregation {dateField :: FieldName,
749+ dateInterval :: Interval,
750+ dateFormat :: Maybe Text,
751+ datePreZone :: Maybe Text,
752+ datePostZone :: Maybe Text,
753+ datePreOffset :: Maybe Text,
754+ datePostOffset :: Maybe Text,
755+ dateAggs :: Maybe Aggregations}
756+#+END_SRC haskell
757+
758+The Date Histogram Aggregation works much the same as the Terms
759+Aggregation.
760+
761+Relevant functions include ~mkDateHistogram~, and ~toDateHistogram~
762+
763+#+BEGIN_SRC haskell
764+let dh = DateHistogramAgg (mkDateHistogram (FieldName "postDate") Minute)
765+#+END_SRC
766+
767+Date histograms also accept a ~FractionalInterval~:
768+
769+#+BEGIN_SRC haskell
770+FractionalInterval :: Float -> TimeInterval -> Interval
771+-- TimeInterval is the following:
772+data TimeInterval = Weeks | Days | Hours | Minutes | Seconds
773+#+END_SRC
774+
775+It can be used as follows:
776+
777+#+BEGIN_SRC haskell
778+let dh = DateHistogramAgg (mkDateHistogram (FieldName "postDate") (FractionalInterval 1.5 Minutes))
779+#+END_SRC
780+
781+The ~DateHistogramResult~ is defined as:
782+
783+#+BEGIN_SRC haskell
784+data DateHistogramResult
785+ = DateHistogramResult {dateKey :: Int,
786+ dateKeyStr :: Maybe Text,
787+ dateDocCount :: Int,
788+ dateHistogramAggs :: Maybe AggregationResults}
789+#+END_SRC
790+
791+It is an instance of ~BucketAggregation~, and can have nested
792+aggregations in each bucket.
793+
794+Buckets can be extracted from a ~AggregationResult~ using
795+~toDateHistogram name~
796+
797+For more information on the Date Histogram Aggregation, see:
798+http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-aggregations-bucket-datehistogram-aggregation.html
799+
643800* Possible future functionality
644801
645802** Span Queries