@@ -22,6 +22,12 @@ module Database.Bloodhound.Types
22 , mkBoolQuery
22 , mkBoolQuery
23 , mkRangeQuery
23 , mkRangeQuery
24 , mkQueryStringQuery
24 , mkQueryStringQuery
27+ , mkTermsScriptAggregation
25 , omitNulls
31 , omitNulls
26 , Version(..)
32 , Version(..)
27 , Status(..)
33 , Status(..)
@@ -143,16 +149,33 @@ module Database.Bloodhound.Types
143 , FieldOrFields(..)
149 , FieldOrFields(..)
144 , Monoid(..)
150 , Monoid(..)
145 , ToJSON(..)
151 , ToJSON(..)
155+ , CollectionMode(..)
160+ , AggregationResults
162+ , BucketAggregation(..)
163+ , TermsAggregation(..)
164+ , DateHistogramAggregation(..)
166+ , DateHistogramResult
148import Control.Applicative
169import Control.Applicative
149import Data.Aeson
170import Data.Aeson
171+import Data.Aeson.Types (parseMaybe)
150import qualified Data.ByteString.Lazy.Char8 as L
172import qualified Data.ByteString.Lazy.Char8 as L
151import Data.List (nub)
173import Data.List (nub)
152import Data.List.NonEmpty (NonEmpty (..))
174import Data.List.NonEmpty (NonEmpty (..))
153import Data.Monoid
175import Data.Monoid
154import Data.Text (Text)
176import Data.Text (Text)
155import qualified Data.Text as T
177import qualified Data.Text as T
178+import qualified Data.Map.Strict as M
156import Data.Time.Clock (UTCTime)
179import Data.Time.Clock (UTCTime)
157import qualified Data.Vector as V
180import qualified Data.Vector as V
158import GHC.Generics (Generic)
181import GHC.Generics (Generic)
@@ -473,9 +496,10 @@ type TrackSortScores = Bool
473type From = Int
496type From = Int
474type Size = Int
497type Size = Int
476−data Search = Search { queryBody :: Maybe Query
499+data Search = Search { queryBody :: Maybe Query
477− , filterBody :: Maybe Filter
500+ , filterBody :: Maybe Filter
478− , sortBody :: Maybe Sort
501+ , sortBody :: Maybe Sort
502+ , aggBody :: Maybe Aggregations
479 -- default False
503 -- default False
480 , trackSortScores :: TrackSortScores
504 , trackSortScores :: TrackSortScores
481 , from :: From
505 , from :: From
@@ -915,10 +939,11 @@ data DistanceRange =
915 , distanceTo :: Distance } deriving (Eq, Show)
939 , distanceTo :: Distance } deriving (Eq, Show)
917data FromJSON a => SearchResult a =
941data FromJSON a => SearchResult a =
918− SearchResult { took :: Int
942+ SearchResult { took :: Int
919− , timedOut :: Bool
943+ , timedOut :: Bool
920− , shards :: ShardResult
944+ , shards :: ShardResult
921− , searchHits :: SearchHits a } deriving (Eq, Show)
945+ , searchHits :: SearchHits a
946+ , aggregations :: Maybe AggregationResults } deriving (Eq, Show)
923type Score = Double
948type Score = Double
@@ -942,6 +967,199 @@ data ShardResult =
942showText :: Show a => a -> Text
967showText :: Show a => a -> Text
943showText = T.pack . show
968showText = T.pack . show
970+type Aggregations = M.Map Text Aggregation
972+emptyAggregations :: Aggregations
973+emptyAggregations = M.empty
975+mkAggregations :: Text -> Aggregation -> Aggregations
976+mkAggregations name aggregation = M.insert name aggregation emptyAggregations
978+data TermOrder = TermOrder{ termSortField :: Text
979+ , termSortOrder :: SortOrder } deriving (Eq, Show)
981+data TermInclusion = TermInclusion Text
982+ | TermPattern Text Text deriving (Eq, Show)
984+data CollectionMode = BreadthFirst
985+ | DepthFirst deriving (Eq, Show)
987+data ExecutionHint = Ordinals
989+ | GlobalOrdinalsHash
990+ | GlobalOrdinalsLowCardinality
991+ | Map deriving(Eq, Show)
993+data TimeInterval = Weeks
997+ | Seconds deriving (Eq)
1007+ | FractionalInterval Float TimeInterval deriving (Eq, Show)
1009+data Aggregation = TermsAgg TermsAggregation
1010+ | DateHistogramAgg DateHistogramAggregation deriving (Eq, Show)
1013+data TermsAggregation = TermsAggregation { term :: Either Text Text
1014+ , termInclude :: Maybe TermInclusion
1015+ , termExclude :: Maybe TermInclusion
1016+ , termOrder :: Maybe TermOrder
1017+ , termMinDocCount :: Maybe Int
1018+ , termSize :: Maybe Int
1019+ , termShardSize :: Maybe Int
1020+ , termCollectMode :: Maybe CollectionMode
1021+ , termExecutionHint :: Maybe ExecutionHint
1022+ , termAggs :: Maybe Aggregations
1023+ } deriving (Eq, Show)
1025+data DateHistogramAggregation = DateHistogramAggregation { dateField :: FieldName
1026+ , dateInterval :: Interval
1027+ , dateFormat :: Maybe Text
1028+ , datePreZone :: Maybe Text
1029+ , datePostZone :: Maybe Text
1030+ , datePreOffset :: Maybe Text
1031+ , datePostOffset :: Maybe Text
1032+ , dateAggs :: Maybe Aggregations
1033+ } deriving (Eq, Show)
1036+mkTermsAggregation :: Text -> TermsAggregation
1037+mkTermsAggregation t = TermsAggregation (Left t) Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
1039+mkTermsScriptAggregation :: Text -> TermsAggregation
1040+mkTermsScriptAggregation t = TermsAggregation (Right t) Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
1042+mkDateHistogram :: FieldName -> Interval -> DateHistogramAggregation
1043+mkDateHistogram t i = DateHistogramAggregation t i Nothing Nothing Nothing Nothing Nothing Nothing
1045+instance ToJSON TermOrder where
1046+ toJSON (TermOrder termSortField termSortOrder) = object [termSortField .= termSortOrder]
1048+instance ToJSON TermInclusion where
1049+ toJSON (TermInclusion x) = toJSON x
1050+ toJSON (TermPattern pattern flags) = omitNulls [ "pattern" .= pattern,
1053+instance ToJSON CollectionMode where
1054+ toJSON BreadthFirst = "breadth_first"
1055+ toJSON DepthFirst = "depth_first"
1057+instance ToJSON ExecutionHint where
1058+ toJSON Ordinals = "ordinals"
1059+ toJSON GlobalOrdinals = "global_ordinals"
1060+ toJSON GlobalOrdinalsHash = "global_ordinals_hash"
1061+ toJSON GlobalOrdinalsLowCardinality = "global_ordinals_low_cardinality"
1064+instance ToJSON Interval where
1065+ toJSON Year = "year"
1066+ toJSON Quarter = "quarter"
1067+ toJSON Month = "month"
1068+ toJSON Week = "week"
1070+ toJSON Hour = "hour"
1071+ toJSON Minute = "minute"
1072+ toJSON Second = "second"
1073+ toJSON (FractionalInterval fraction interval) = toJSON $ show fraction ++ show interval
1075+instance Show TimeInterval where
1082+instance ToJSON Aggregation where
1083+ toJSON (TermsAgg (TermsAggregation term include exclude order minDocCount size shardSize collectMode executionHint aggs)) =
1084+ omitNulls ["terms" .= omitNulls [ toJSON' term,
1085+ "include" .= toJSON include,
1086+ "exclude" .= toJSON exclude,
1087+ "order" .= toJSON order,
1088+ "min_doc_count" .= toJSON minDocCount,
1089+ "size" .= toJSON size,
1090+ "shard_size" .= toJSON shardSize,
1091+ "collect_mode" .= toJSON collectMode,
1092+ "execution_hint" .= toJSON executionHint
1094+ "aggs" .= toJSON aggs ]
1096+ toJSON' x = case x of { Left y -> "field" .= toJSON y; Right y -> "script" .= toJSON y }
1098+ toJSON (DateHistogramAgg (DateHistogramAggregation field interval format preZone postZone preOffset postOffset aggs)) =
1099+ omitNulls ["date_histogram" .= omitNulls [ "field" .= toJSON field,
1100+ "interval" .= toJSON interval,
1101+ "format" .= toJSON format,
1102+ "pre_zone" .= toJSON preZone,
1103+ "post_zone" .= toJSON postZone,
1104+ "pre_offset" .= toJSON preOffset,
1105+ "post_offset" .= toJSON postOffset
1107+ "aggs" .= toJSON aggs ]
1109+type AggregationResults = M.Map Text Value
1111+class BucketAggregation a where
1113+ docCount :: a -> Int
1114+ aggs :: a -> Maybe AggregationResults
1117+data (FromJSON a, BucketAggregation a) => Bucket a = Bucket { buckets :: [a]} deriving (Show)
1119+data TermsResult = TermsResult { termKey :: Text
1120+ , termsDocCount :: Int
1121+ , termsAggs :: Maybe AggregationResults } deriving (Show)
1123+data DateHistogramResult = DateHistogramResult { dateKey :: Int
1124+ , dateKeyStr :: Maybe Text
1125+ , dateDocCount :: Int
1126+ , dateHistogramAggs :: Maybe AggregationResults } deriving (Show)
1128+toTerms :: Text -> AggregationResults -> Maybe (Bucket TermsResult)
1129+toTerms t a = M.lookup t a >>= deserialize
1130+ where deserialize = parseMaybe parseJSON
1132+toDateHistogram :: Text -> AggregationResults -> Maybe (Bucket DateHistogramResult)
1133+toDateHistogram t a = M.lookup t a >>= deserialize
1134+ where deserialize = parseMaybe parseJSON
1136+instance BucketAggregation TermsResult where
1138+ docCount = termsDocCount
1141+instance BucketAggregation DateHistogramResult where
1142+ key = showText . dateKey
1143+ docCount = dateDocCount
1144+ aggs = dateHistogramAggs
1146+instance (FromJSON a, BucketAggregation a) => FromJSON (Bucket a) where
1147+ parseJSON (Object v) = Bucket <$>
1149+ parseJSON _ = mempty
1151+instance FromJSON TermsResult where
1152+ parseJSON (Object v) = TermsResult <$>
1154+ v .: "doc_count" <*>
1155+ v .:? "aggregations"
1157+instance FromJSON DateHistogramResult where
1158+ parseJSON (Object v) = DateHistogramResult <$>
1160+ v .:? "key_as_string" <*>
1161+ v .: "doc_count" <*>
1162+ v .:? "aggregations"
946instance Monoid Filter where
1164instance Monoid Filter where
947 mempty = IdentityFilter
1165 mempty = IdentityFilter
@@ -1536,10 +1754,11 @@ instance (FromJSON a) => FromJSON (EsResult a) where
1538instance ToJSON Search where
1756instance ToJSON Search where
1539− toJSON (Search query sFilter sort sTrackSortScores sFrom sSize) =
1757+ toJSON (Search query sFilter sort aggs sTrackSortScores sFrom sSize) =
1540 omitNulls [ "query" .= query
1758 omitNulls [ "query" .= query
1541 , "filter" .= sFilter
1759 , "filter" .= sFilter
1542 , "sort" .= sort
1760 , "sort" .= sort
1761+ , "aggregations" .= aggs
1543 , "from" .= sFrom
1762 , "from" .= sFrom
1544 , "size" .= sSize
1763 , "size" .= sSize
1545 , "track_scores" .= sTrackSortScores ]
1764 , "track_scores" .= sTrackSortScores ]
@@ -1677,10 +1896,11 @@ instance ToJSON BoolMatch where
1678instance (FromJSON a) => FromJSON (SearchResult a) where
1897instance (FromJSON a) => FromJSON (SearchResult a) where
1679 parseJSON (Object v) = SearchResult <$>
1898 parseJSON (Object v) = SearchResult <$>
1680− v .: "took" <*>
1899+ v .: "took" <*>
1681− v .: "timed_out" <*>
1900+ v .: "timed_out" <*>
1682− v .: "_shards" <*>
1901+ v .: "_shards" <*>
1683− v .: "hits"
1902+ v .: "hits" <*>
1903+ v .:? "aggregations"
1684 parseJSON _ = empty
1904 parseJSON _ = empty
1686instance (FromJSON a) => FromJSON (SearchHits a) where
1906instance (FromJSON a) => FromJSON (SearchHits a) where