git.iko.soy/typeable/bloodhound
on master help sign in
Merge pull request #182 from bermanjosh/suggest
79b4f90Chris Allen
src/Database/V1/Bloodhound/Client.hs+3−3
@@ -861,17 +861,17 @@ scanSearch indexName mappingName search = do
861-- syntax if you want to add things like aggregations or highlights while still using
861-- syntax if you want to add things like aggregations or highlights while still using
862-- this helper function.
862-- this helper function.
863mkSearch :: Maybe Query -> Maybe Filter -> Search
863mkSearch :: Maybe Query -> Maybe Filter -> Search
864−mkSearch query filter = Search query filter Nothing Nothing Nothing False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing
864+mkSearch query filter = Search query filter Nothing Nothing Nothing False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing Nothing
865
865
866-- | 'mkAggregateSearch' is a helper function that defaults everything in a 'Search' except for
866-- | 'mkAggregateSearch' is a helper function that defaults everything in a 'Search' except for
867-- the 'Query' and the 'Aggregation'.
867-- the 'Query' and the 'Aggregation'.
868mkAggregateSearch :: Maybe Query -> Aggregations -> Search
868mkAggregateSearch :: Maybe Query -> Aggregations -> Search
869−mkAggregateSearch query mkSearchAggs = Search query Nothing Nothing (Just mkSearchAggs) Nothing False (From 0) (Size 0) SearchTypeQueryThenFetch Nothing Nothing
869+mkAggregateSearch query mkSearchAggs = Search query Nothing Nothing (Just mkSearchAggs) Nothing False (From 0) (Size 0) SearchTypeQueryThenFetch Nothing Nothing Nothing
870
870
871-- | 'mkHighlightSearch' is a helper function that defaults everything in a 'Search' except for
871-- | 'mkHighlightSearch' is a helper function that defaults everything in a 'Search' except for
872-- the 'Query' and the 'Aggregation'.
872-- the 'Query' and the 'Aggregation'.
873mkHighlightSearch :: Maybe Query -> Highlights -> Search
873mkHighlightSearch :: Maybe Query -> Highlights -> Search
874−mkHighlightSearch query searchHighlights = Search query Nothing Nothing Nothing (Just searchHighlights) False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing
874+mkHighlightSearch query searchHighlights = Search query Nothing Nothing Nothing (Just searchHighlights) False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing Nothing
875
875
876-- | 'pageSearch' is a helper function that takes a search and assigns the from
876-- | 'pageSearch' is a helper function that takes a search and assigns the from
877-- and size fields for the search. The from parameter defines the offset
877-- and size fields for the search. The from parameter defines the offset
src/Database/V1/Bloodhound/Types.hs+240−7
@@ -195,6 +195,8 @@ module Database.V1.Bloodhound.Types
195 , RangeQuery(..)
195 , RangeQuery(..)
196 , RegexpQuery(..)
196 , RegexpQuery(..)
197 , QueryString(..)
197 , QueryString(..)
198+ , TemplateQueryInline(..)
199+ , TemplateQueryKeyValuePairs(..)
198 , BooleanOperator(..)
200 , BooleanOperator(..)
199 , ZeroTermsQuery(..)
201 , ZeroTermsQuery(..)
200 , CutoffFrequency(..)
202 , CutoffFrequency(..)
@@ -322,6 +324,15 @@ module Database.V1.Bloodhound.Types
322 , rrGroupRefNum
324 , rrGroupRefNum
323 , mkRRGroupRefNum
325 , mkRRGroupRefNum
324 , RestoreIndexSettings(..)
326 , RestoreIndexSettings(..)
327+ , Suggest(..)
328+ , SuggestType(..)
329+ , PhraseSuggester(..)
330+ , PhraseSuggesterHighlighter(..)
331+ , PhraseSuggesterCollate(..)
332+ , mkPhraseSuggester
333+ , SuggestOptions(..)
334+ , SuggestResponse(..)
335+ , NamedSuggestionResponse(..)
325
336
326 , Aggregation(..)
337 , Aggregation(..)
327 , Aggregations
338 , Aggregations
@@ -376,7 +387,8 @@ import Control.Monad.Writer (MonadWriter)
376import Data.Aeson
387import Data.Aeson
377import Data.Aeson.Types (Pair, Parser,
388import Data.Aeson.Types (Pair, Parser,
378 emptyObject,
389 emptyObject,
379− parseEither, parseMaybe)
390+ parseEither, parseMaybe,
391+ typeMismatch)
380import qualified Data.ByteString.Lazy.Char8 as L
392import qualified Data.ByteString.Lazy.Char8 as L
381import Data.Char
393import Data.Char
382import Data.Hashable (Hashable)
394import Data.Hashable (Hashable)
@@ -1091,7 +1103,7 @@ unpackId (DocId docId) = docId
1091
1103
1092type TrackSortScores = Bool
1104type TrackSortScores = Bool
1093newtype From = From Int deriving (Eq, Read, Show, Generic, ToJSON)
1105newtype From = From Int deriving (Eq, Read, Show, Generic, ToJSON)
1094−newtype Size = Size Int deriving (Eq, Read, Show, Generic, ToJSON)
1106+newtype Size = Size Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1095
1107
1096data Search = Search { queryBody :: Maybe Query
1108data Search = Search { queryBody :: Maybe Query
1097 , filterBody :: Maybe Filter
1109 , filterBody :: Maybe Filter
@@ -1104,7 +1116,9 @@ data Search = Search { queryBody :: Maybe Query
1104 , size :: Size
1116 , size :: Size
1105 , searchType :: SearchType
1117 , searchType :: SearchType
1106 , fields :: Maybe [FieldName]
1118 , fields :: Maybe [FieldName]
1119+ , source :: Maybe Source
1120+ , suggestBody :: Maybe Suggest -- ^ Only one Suggestion request / response per Search is supported.
1107− , source :: Maybe Source } deriving (Eq, Read, Show, Generic, Typeable)
1121+ } deriving (Eq, Read, Show, Generic, Typeable)
1108
1122
1109data SearchType = SearchTypeQueryThenFetch
1123data SearchType = SearchTypeQueryThenFetch
1110 | SearchTypeDfsQueryThenFetch
1124 | SearchTypeDfsQueryThenFetch
@@ -1211,6 +1225,7 @@ data Query =
1211 | QuerySimpleQueryStringQuery SimpleQueryStringQuery
1225 | QuerySimpleQueryStringQuery SimpleQueryStringQuery
1212 | QueryRangeQuery RangeQuery
1226 | QueryRangeQuery RangeQuery
1213 | QueryRegexpQuery RegexpQuery
1227 | QueryRegexpQuery RegexpQuery
1228+ | QueryTemplateQueryInline TemplateQueryInline
1214 deriving (Eq, Read, Show, Generic, Typeable)
1229 deriving (Eq, Read, Show, Generic, Typeable)
1215
1230
1216data RegexpQuery =
1231data RegexpQuery =
@@ -1635,13 +1650,48 @@ data DistanceRange =
1635 DistanceRange { distanceFrom :: Distance
1650 DistanceRange { distanceFrom :: Distance
1636 , distanceTo :: Distance } deriving (Eq, Read, Show, Generic, Typeable)
1651 , distanceTo :: Distance } deriving (Eq, Read, Show, Generic, Typeable)
1637
1652
1653+type TemplateQueryKey = Text
1654+type TemplateQueryValue = Text
1655+
1656+newtype TemplateQueryKeyValuePairs = TemplateQueryKeyValuePairs (HM.HashMap TemplateQueryKey TemplateQueryValue)
1657+ deriving (Eq, Read, Show, Generic, Typeable)
1658+
1659+instance ToJSON TemplateQueryKeyValuePairs where
1660+ toJSON (TemplateQueryKeyValuePairs x) = Object $ HM.map toJSON x
1661+
1662+instance FromJSON TemplateQueryKeyValuePairs where
1663+ parseJSON (Object o) = pure . TemplateQueryKeyValuePairs $ HM.mapMaybe getValue o
1664+ where getValue (String x) = Just x
1665+ getValue _ = Nothing
1666+ parseJSON _ = fail "error parsing TemplateQueryKeyValuePairs"
1667+
1668+data TemplateQueryInline =
1669+ TemplateQueryInline { inline :: Query
1670+ , params :: TemplateQueryKeyValuePairs
1671+ }
1672+ deriving (Eq, Read, Show, Generic, Typeable)
1673+
1674+instance ToJSON TemplateQueryInline where
1675+ toJSON TemplateQueryInline{..} = object [ "query" .= inline
1676+ , "params" .= params
1677+ ]
1678+
1679+instance FromJSON TemplateQueryInline where
1680+ parseJSON = withObject "TemplateQueryInline" parse
1681+ where parse o = TemplateQueryInline
1682+ <$> o .: "query"
1683+ <*> o .: "params"
1684+
1638data SearchResult a =
1685data SearchResult a =
1639 SearchResult { took :: Int
1686 SearchResult { took :: Int
1640 , timedOut :: Bool
1687 , timedOut :: Bool
1641 , shards :: ShardResult
1688 , shards :: ShardResult
1642 , searchHits :: SearchHits a
1689 , searchHits :: SearchHits a
1643 , aggregations :: Maybe AggregationResults
1690 , aggregations :: Maybe AggregationResults
1691+ , scrollId :: Maybe ScrollId
1692+ , suggest :: Maybe NamedSuggestionResponse -- ^ Only one Suggestion request / response per Search is supported.
1693+ }
1644− , scrollId :: Maybe ScrollId } deriving (Eq, Read, Show, Generic, Typeable)
1694+ deriving (Eq, Read, Show, Generic, Typeable)
1645
1695
1646newtype ScrollId = ScrollId Text deriving (Eq, Read, Show, Generic, Ord, ToJSON, FromJSON)
1696newtype ScrollId = ScrollId Text deriving (Eq, Read, Show, Generic, Ord, ToJSON, FromJSON)
1647
1697
@@ -2404,6 +2454,9 @@ instance ToJSON Query where
2404 toJSON (QuerySimpleQueryStringQuery query) =
2454 toJSON (QuerySimpleQueryStringQuery query) =
2405 object [ "simple_query_string" .= query ]
2455 object [ "simple_query_string" .= query ]
2406
2456
2457+ toJSON (QueryTemplateQueryInline templateQuery) =
2458+ object [ "template" .= templateQuery ]
2459+
2407instance FromJSON Query where
2460instance FromJSON Query where
2408 parseJSON v = withObject "Query" parse v
2461 parseJSON v = withObject "Query" parse v
2409 where parse o = termQuery `taggedWith` "term"
2462 where parse o = termQuery `taggedWith` "term"
@@ -2433,6 +2486,7 @@ instance FromJSON Query where
2433 <|> queryRangeQuery `taggedWith` "range"
2486 <|> queryRangeQuery `taggedWith` "range"
2434 <|> queryRegexpQuery `taggedWith` "regexp"
2487 <|> queryRegexpQuery `taggedWith` "regexp"
2435 <|> querySimpleQueryStringQuery `taggedWith` "simple_query_string"
2488 <|> querySimpleQueryStringQuery `taggedWith` "simple_query_string"
2489+ <|> queryTemplateQueryInline `taggedWith` "template"
2436 where taggedWith parser k = parser =<< o .: k
2490 where taggedWith parser k = parser =<< o .: k
2437 termQuery = fieldTagged $ \(FieldName fn) o ->
2491 termQuery = fieldTagged $ \(FieldName fn) o ->
2438 TermQuery <$> (Term fn <$> o .: "value") <*> o .:? "boost"
2492 TermQuery <$> (Term fn <$> o .: "value") <*> o .:? "boost"
@@ -2474,6 +2528,7 @@ instance FromJSON Query where
2474 queryRangeQuery = pure . QueryRangeQuery
2528 queryRangeQuery = pure . QueryRangeQuery
2475 queryRegexpQuery = pure . QueryRegexpQuery
2529 queryRegexpQuery = pure . QueryRegexpQuery
2476 querySimpleQueryStringQuery = pure . QuerySimpleQueryStringQuery
2530 querySimpleQueryStringQuery = pure . QuerySimpleQueryStringQuery
2531+ queryTemplateQueryInline = pure . QueryTemplateQueryInline
2477
2532
2478
2533
2479omitNulls :: [(Text, Value)] -> Value
2534omitNulls :: [(Text, Value)] -> Value
@@ -3412,7 +3467,7 @@ instance FromJSON SearchAliasRouting where
3412 where parse t = SearchAliasRouting <$> parseNEJSON (String <$> T.splitOn "," t)
3467 where parse t = SearchAliasRouting <$> parseNEJSON (String <$> T.splitOn "," t)
3413
3468
3414instance ToJSON Search where
3469instance ToJSON Search where
3415− toJSON (Search query sFilter sort searchAggs highlight sTrackSortScores sFrom sSize _ sFields sSource) =
3470+ toJSON (Search query sFilter sort searchAggs highlight sTrackSortScores sFrom sSize _ sFields sSource sSuggest) =
3416 omitNulls [ "query" .= query
3471 omitNulls [ "query" .= query
3417 , "filter" .= sFilter
3472 , "filter" .= sFilter
3418 , "sort" .= sort
3473 , "sort" .= sort
@@ -3422,7 +3477,8 @@ instance ToJSON Search where
3422 , "size" .= sSize
3477 , "size" .= sSize
3423 , "track_scores" .= sTrackSortScores
3478 , "track_scores" .= sTrackSortScores
3424 , "fields" .= sFields
3479 , "fields" .= sFields
3425− , "_source" .= sSource]
3480+ , "_source" .= sSource
3481+ , "suggest" .= sSuggest]
3426
3482
3427
3483
3428instance ToJSON Source where
3484instance ToJSON Source where
@@ -3772,7 +3828,8 @@ instance (FromJSON a) => FromJSON (SearchResult a) where
3772 v .: "_shards" <*>
3828 v .: "_shards" <*>
3773 v .: "hits" <*>
3829 v .: "hits" <*>
3774 v .:? "aggregations" <*>
3830 v .:? "aggregations" <*>
3775− v .:? "_scroll_id"
3831+ v .:? "_scroll_id" <*>
3832+ v .:? "suggest"
3776 parseJSON _ = empty
3833 parseJSON _ = empty
3777
3834
3778instance (FromJSON a) => FromJSON (SearchHits a) where
3835instance (FromJSON a) => FromJSON (SearchHits a) where
@@ -5277,3 +5334,179 @@ newtype MaybeNA a = MaybeNA { unMaybeNA :: Maybe a }
5277instance FromJSON a => FromJSON (MaybeNA a) where
5334instance FromJSON a => FromJSON (MaybeNA a) where
5278 parseJSON (String "NA") = pure $ MaybeNA Nothing
5335 parseJSON (String "NA") = pure $ MaybeNA Nothing
5279 parseJSON o = MaybeNA . Just <$> parseJSON o
5336 parseJSON o = MaybeNA . Just <$> parseJSON o
5337+
5338+
5339+data Suggest = Suggest { suggestText :: Text
5340+ , suggestName :: Text
5341+ , suggestType :: SuggestType
5342+ }
5343+ deriving (Show, Generic, Eq, Read, Typeable)
5344+
5345+instance ToJSON Suggest where
5346+ toJSON Suggest{..} = object [ "text" .= suggestText
5347+ , suggestName .= suggestType
5348+ ]
5349+
5350+instance FromJSON Suggest where
5351+ parseJSON (Object o) = do
5352+ suggestText' <- o .: "text"
5353+ let dropTextList = HM.toList $ HM.filterWithKey (\x _ -> x /= "text") o
5354+ suggestName' <- case dropTextList of
5355+ [(x, _)] -> return x
5356+ _ -> fail "error parsing Suggest field name"
5357+ suggestType' <- o .: suggestName'
5358+ return $ Suggest suggestText' suggestName' suggestType'
5359+ parseJSON x = typeMismatch "Suggest" x
5360+
5361+data SuggestType = SuggestTypePhraseSuggester PhraseSuggester
5362+ deriving (Show, Generic, Eq, Read, Typeable)
5363+
5364+instance ToJSON SuggestType where
5365+ toJSON (SuggestTypePhraseSuggester x) = object ["phrase" .= x]
5366+
5367+instance FromJSON SuggestType where
5368+ parseJSON = withObject "SuggestType" parse
5369+ where parse o = phraseSuggester `taggedWith` "phrase"
5370+ where taggedWith parser k = parser =<< o .: k
5371+ phraseSuggester = pure . SuggestTypePhraseSuggester
5372+
5373+data PhraseSuggester =
5374+ PhraseSuggester { phraseSuggesterField :: FieldName
5375+ , phraseSuggesterGramSize :: Maybe Int
5376+ , phraseSuggesterRealWordErrorLikelihood :: Maybe Int
5377+ , phraseSuggesterConfidence :: Maybe Int
5378+ , phraseSuggesterMaxErrors :: Maybe Int
5379+ , phraseSuggesterSeparator :: Maybe Text
5380+ , phraseSuggesterSize :: Maybe Size
5381+ , phraseSuggesterAnalyzer :: Maybe Analyzer
5382+ , phraseSuggesterShardSize :: Maybe Int
5383+ , phraseSuggesterHighlight :: Maybe PhraseSuggesterHighlighter
5384+ , phraseSuggesterCollate :: Maybe PhraseSuggesterCollate
5385+ }
5386+ deriving (Show, Generic, Eq, Read, Typeable)
5387+
5388+instance ToJSON PhraseSuggester where
5389+ toJSON PhraseSuggester{..} = omitNulls [ "field" .= phraseSuggesterField
5390+ , "gram_size" .= phraseSuggesterGramSize
5391+ , "real_word_error_likelihood" .= phraseSuggesterRealWordErrorLikelihood
5392+ , "confidence" .= phraseSuggesterConfidence
5393+ , "max_errors" .= phraseSuggesterMaxErrors
5394+ , "separator" .= phraseSuggesterSeparator
5395+ , "size" .= phraseSuggesterSize
5396+ , "analyzer" .= phraseSuggesterAnalyzer
5397+ , "shard_size" .= phraseSuggesterShardSize
5398+ , "highlight" .= phraseSuggesterHighlight
5399+ , "collate" .= phraseSuggesterCollate
5400+ ]
5401+
5402+instance FromJSON PhraseSuggester where
5403+ parseJSON = withObject "PhraseSuggester" parse
5404+ where parse o = PhraseSuggester
5405+ <$> o .: "field"
5406+ <*> o .:? "gram_size"
5407+ <*> o .:? "real_word_error_likelihood"
5408+ <*> o .:? "confidence"
5409+ <*> o .:? "max_errors"
5410+ <*> o .:? "separator"
5411+ <*> o .:? "size"
5412+ <*> o .:? "analyzer"
5413+ <*> o .:? "shard_size"
5414+ <*> o .:? "highlight"
5415+ <*> o .:? "collate"
5416+
5417+mkPhraseSuggester :: FieldName -> PhraseSuggester
5418+mkPhraseSuggester fName =
5419+ PhraseSuggester fName Nothing Nothing Nothing Nothing Nothing Nothing
5420+ Nothing Nothing Nothing Nothing
5421+
5422+data PhraseSuggesterHighlighter =
5423+ PhraseSuggesterHighlighter { phraseSuggesterHighlighterPreTag :: Text
5424+ , phraseSuggesterHighlighterPostTag :: Text
5425+ }
5426+ deriving (Show, Generic, Eq, Read, Typeable)
5427+
5428+instance ToJSON PhraseSuggesterHighlighter where
5429+ toJSON PhraseSuggesterHighlighter{..} =
5430+ object [ "pre_tag" .= phraseSuggesterHighlighterPreTag
5431+ , "post_tag" .= phraseSuggesterHighlighterPostTag
5432+ ]
5433+
5434+instance FromJSON PhraseSuggesterHighlighter where
5435+ parseJSON = withObject "PhraseSuggesterHighlighter" parse
5436+ where parse o = PhraseSuggesterHighlighter
5437+ <$> o .: "pre_tag"
5438+ <*> o .: "post_tag"
5439+
5440+data PhraseSuggesterCollate =
5441+ PhraseSuggesterCollate { phraseSuggesterCollateTemplateQuery :: TemplateQueryInline
5442+ , phraseSuggesterCollatePrune :: Bool
5443+ }
5444+ deriving (Show, Generic, Eq, Read, Typeable)
5445+
5446+instance ToJSON PhraseSuggesterCollate where
5447+ toJSON PhraseSuggesterCollate{..} = object [ "query" .= object
5448+ [ "inline" .= (inline phraseSuggesterCollateTemplateQuery)
5449+ ]
5450+ , "params" .= (params phraseSuggesterCollateTemplateQuery)
5451+ , "prune" .= phraseSuggesterCollatePrune
5452+ ]
5453+
5454+instance FromJSON PhraseSuggesterCollate where
5455+ parseJSON (Object o) = do
5456+ query' <- o .: "query"
5457+ inline' <- query' .: "inline"
5458+ params' <- o .: "params"
5459+ prune' <- o .:? "prune" .!= False
5460+ return $ PhraseSuggesterCollate (TemplateQueryInline inline' params') prune'
5461+ parseJSON x = typeMismatch "PhraseSuggesterCollate" x
5462+
5463+mkPhraseSuggesterCollate :: TemplateQueryInline -> PhraseSuggesterCollate
5464+mkPhraseSuggesterCollate tQuery = PhraseSuggesterCollate tQuery False
5465+
5466+data SuggestOptions =
5467+ SuggestOptions { suggestOptionsText :: Text
5468+ , suggestOptionsScore :: Double
5469+ , suggestOptionsFreq :: Maybe Int
5470+ , suggestOptionsHighlighted :: Maybe Text
5471+ }
5472+ deriving (Eq, Read, Show)
5473+
5474+instance FromJSON SuggestOptions where
5475+ parseJSON = withObject "SuggestOptions" parse
5476+ where parse o = SuggestOptions
5477+ <$> o .: "text"
5478+ <*> o .: "score"
5479+ <*> o .:? "freq"
5480+ <*> o .:? "highlighted"
5481+
5482+data SuggestResponse =
5483+ SuggestResponse { suggestResponseText :: Text
5484+ , suggestResponseOffset :: Int
5485+ , suggestResponseLength :: Int
5486+ , suggestResponseOptions :: [SuggestOptions]
5487+ }
5488+ deriving (Eq, Read, Show)
5489+
5490+instance FromJSON SuggestResponse where
5491+ parseJSON = withObject "SuggestResponse" parse
5492+ where parse o = SuggestResponse
5493+ <$> o .: "text"
5494+ <*> o .: "offset"
5495+ <*> o .: "length"
5496+ <*> o .: "options"
5497+
5498+data NamedSuggestionResponse =
5499+ NamedSuggestionResponse { nsrName :: Text
5500+ , nsrResponses :: [SuggestResponse]
5501+ }
5502+ deriving (Eq, Read, Show)
5503+
5504+instance FromJSON NamedSuggestionResponse where
5505+ parseJSON (Object o) = do
5506+ suggestionName' <- case HM.toList o of
5507+ [(x, _)] -> return x
5508+ _ -> fail "error parsing NamedSuggestionResponse name"
5509+ suggestionResponses' <- o .: suggestionName'
5510+ return $ NamedSuggestionResponse suggestionName' suggestionResponses'
5511+
5512+ parseJSON x = typeMismatch "NamedSuggestionResponse" x
src/Database/V5/Bloodhound/Client.hs+3−3
@@ -1044,7 +1044,7 @@ scanSearch indexName mappingName search = do
1044-- >>> mkSearch (Just query) Nothing
1044-- >>> mkSearch (Just query) Nothing
1045-- Search {queryBody = Just (TermQuery (Term {termField = "user", termValue = "bitemyapp"}) Nothing), filterBody = Nothing, sortBody = Nothing, aggBody = Nothing, highlight = Nothing, trackSortScores = False, from = From 0, size = Size 10, searchType = SearchTypeQueryThenFetch, fields = Nothing, source = Nothing}
1045-- Search {queryBody = Just (TermQuery (Term {termField = "user", termValue = "bitemyapp"}) Nothing), filterBody = Nothing, sortBody = Nothing, aggBody = Nothing, highlight = Nothing, trackSortScores = False, from = From 0, size = Size 10, searchType = SearchTypeQueryThenFetch, fields = Nothing, source = Nothing}
1046mkSearch :: Maybe Query -> Maybe Filter -> Search
1046mkSearch :: Maybe Query -> Maybe Filter -> Search
1047−mkSearch query filter = Search query filter Nothing Nothing Nothing False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing
1047+mkSearch query filter = Search query filter Nothing Nothing Nothing False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing Nothing
1048
1048
1049-- | 'mkAggregateSearch' is a helper function that defaults everything in a 'Search' except for
1049-- | 'mkAggregateSearch' is a helper function that defaults everything in a 'Search' except for
1050-- the 'Query' and the 'Aggregation'.
1050-- the 'Query' and the 'Aggregation'.
@@ -1054,7 +1054,7 @@ mkSearch query filter = Search query filter Nothing Nothing Nothing False (From
1054-- TermsAgg (TermsAggregation {term = Left "user", termInclude = Nothing, termExclude = Nothing, termOrder = Nothing, termMinDocCount = Nothing, termSize = Nothing, termShardSize = Nothing, termCollectMode = Just BreadthFirst, termExecutionHint = Nothing, termAggs = Nothing})
1054-- TermsAgg (TermsAggregation {term = Left "user", termInclude = Nothing, termExclude = Nothing, termOrder = Nothing, termMinDocCount = Nothing, termSize = Nothing, termShardSize = Nothing, termCollectMode = Just BreadthFirst, termExecutionHint = Nothing, termAggs = Nothing})
1055-- >>> let myAggregation = mkAggregateSearch Nothing $ mkAggregations "users" terms
1055-- >>> let myAggregation = mkAggregateSearch Nothing $ mkAggregations "users" terms
1056mkAggregateSearch :: Maybe Query -> Aggregations -> Search
1056mkAggregateSearch :: Maybe Query -> Aggregations -> Search
1057−mkAggregateSearch query mkSearchAggs = Search query Nothing Nothing (Just mkSearchAggs) Nothing False (From 0) (Size 0) SearchTypeQueryThenFetch Nothing Nothing
1057+mkAggregateSearch query mkSearchAggs = Search query Nothing Nothing (Just mkSearchAggs) Nothing False (From 0) (Size 0) SearchTypeQueryThenFetch Nothing Nothing Nothing
1058
1058
1059-- | 'mkHighlightSearch' is a helper function that defaults everything in a 'Search' except for
1059-- | 'mkHighlightSearch' is a helper function that defaults everything in a 'Search' except for
1060-- the 'Query' and the 'Aggregation'.
1060-- the 'Query' and the 'Aggregation'.
@@ -1063,7 +1063,7 @@ mkAggregateSearch query mkSearchAggs = Search query Nothing Nothing (Just mkSear
1063-- >>> let testHighlight = Highlights Nothing [FieldHighlight (FieldName "message") Nothing]
1063-- >>> let testHighlight = Highlights Nothing [FieldHighlight (FieldName "message") Nothing]
1064-- >>> let search = mkHighlightSearch (Just query) testHighlight
1064-- >>> let search = mkHighlightSearch (Just query) testHighlight
1065mkHighlightSearch :: Maybe Query -> Highlights -> Search
1065mkHighlightSearch :: Maybe Query -> Highlights -> Search
1066−mkHighlightSearch query searchHighlights = Search query Nothing Nothing Nothing (Just searchHighlights) False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing
1066+mkHighlightSearch query searchHighlights = Search query Nothing Nothing Nothing (Just searchHighlights) False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing Nothing
1067
1067
1068-- | 'pageSearch' is a helper function that takes a search and assigns the from
1068-- | 'pageSearch' is a helper function that takes a search and assigns the from
1069-- and size fields for the search. The from parameter defines the offset
1069-- and size fields for the search. The from parameter defines the offset
src/Database/V5/Bloodhound/Types.hs+242−9
@@ -196,6 +196,8 @@ module Database.V5.Bloodhound.Types
196 , RangeQuery(..)
196 , RangeQuery(..)
197 , RegexpQuery(..)
197 , RegexpQuery(..)
198 , QueryString(..)
198 , QueryString(..)
199+ , TemplateQueryInline(..)
200+ , TemplateQueryKeyValuePairs(..)
199 , BooleanOperator(..)
201 , BooleanOperator(..)
200 , ZeroTermsQuery(..)
202 , ZeroTermsQuery(..)
201 , CutoffFrequency(..)
203 , CutoffFrequency(..)
@@ -323,6 +325,15 @@ module Database.V5.Bloodhound.Types
323 , rrGroupRefNum
325 , rrGroupRefNum
324 , mkRRGroupRefNum
326 , mkRRGroupRefNum
325 , RestoreIndexSettings(..)
327 , RestoreIndexSettings(..)
328+ , Suggest(..)
329+ , SuggestType(..)
330+ , PhraseSuggester(..)
331+ , PhraseSuggesterHighlighter(..)
332+ , PhraseSuggesterCollate(..)
333+ , mkPhraseSuggester
334+ , SuggestOptions(..)
335+ , SuggestResponse(..)
336+ , NamedSuggestionResponse(..)
326
337
327 , Aggregation(..)
338 , Aggregation(..)
328 , Aggregations
339 , Aggregations
@@ -378,7 +389,8 @@ import Control.Monad.Writer (MonadWriter)
378import Data.Aeson
389import Data.Aeson
379import Data.Aeson.Types (Pair, Parser,
390import Data.Aeson.Types (Pair, Parser,
380 emptyObject,
391 emptyObject,
381− parseEither, parseMaybe)
392+ parseEither, parseMaybe,
393+ typeMismatch)
382import qualified Data.ByteString.Lazy.Char8 as L
394import qualified Data.ByteString.Lazy.Char8 as L
383import Data.Char
395import Data.Char
384import Data.Hashable (Hashable)
396import Data.Hashable (Hashable)
@@ -1095,7 +1107,7 @@ unpackId (DocId docId) = docId
1095
1107
1096type TrackSortScores = Bool
1108type TrackSortScores = Bool
1097newtype From = From Int deriving (Eq, Read, Show, Generic, ToJSON)
1109newtype From = From Int deriving (Eq, Read, Show, Generic, ToJSON)
1098−newtype Size = Size Int deriving (Eq, Read, Show, Generic, ToJSON)
1110+newtype Size = Size Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON)
1099
1111
1100data Search = Search { queryBody :: Maybe Query
1112data Search = Search { queryBody :: Maybe Query
1101 , filterBody :: Maybe Filter
1113 , filterBody :: Maybe Filter
@@ -1108,7 +1120,9 @@ data Search = Search { queryBody :: Maybe Query
1108 , size :: Size
1120 , size :: Size
1109 , searchType :: SearchType
1121 , searchType :: SearchType
1110 , fields :: Maybe [FieldName]
1122 , fields :: Maybe [FieldName]
1123+ , source :: Maybe Source
1124+ , suggestBody :: Maybe Suggest -- ^ Only one Suggestion request / response per Search is supported.
1111− , source :: Maybe Source } deriving (Eq, Read, Show, Generic, Typeable)
1125+ } deriving (Eq, Read, Show, Generic, Typeable)
1112
1126
1113data SearchType = SearchTypeQueryThenFetch
1127data SearchType = SearchTypeQueryThenFetch
1114 | SearchTypeDfsQueryThenFetch
1128 | SearchTypeDfsQueryThenFetch
@@ -1211,6 +1225,7 @@ data Query =
1211 | QueryRegexpQuery RegexpQuery
1225 | QueryRegexpQuery RegexpQuery
1212 | QueryExistsQuery FieldName
1226 | QueryExistsQuery FieldName
1213 | QueryMatchNoneQuery
1227 | QueryMatchNoneQuery
1228+ | QueryTemplateQueryInline TemplateQueryInline
1214 deriving (Eq, Read, Show, Generic, Typeable)
1229 deriving (Eq, Read, Show, Generic, Typeable)
1215
1230
1216-- | As of Elastic 2.0, 'Filters' are just 'Queries' housed in a Bool Query, and
1231-- | As of Elastic 2.0, 'Filters' are just 'Queries' housed in a Bool Query, and
@@ -1622,13 +1637,49 @@ data DistanceRange =
1622 DistanceRange { distanceFrom :: Distance
1637 DistanceRange { distanceFrom :: Distance
1623 , distanceTo :: Distance } deriving (Eq, Read, Show, Generic, Typeable)
1638 , distanceTo :: Distance } deriving (Eq, Read, Show, Generic, Typeable)
1624
1639
1640+type TemplateQueryKey = Text
1641+type TemplateQueryValue = Text
1642+
1643+newtype TemplateQueryKeyValuePairs = TemplateQueryKeyValuePairs (HM.HashMap TemplateQueryKey TemplateQueryValue)
1644+ deriving (Eq, Read, Show, Generic)
1645+
1646+instance ToJSON TemplateQueryKeyValuePairs where
1647+ toJSON (TemplateQueryKeyValuePairs x) = Object $ HM.map toJSON x
1648+
1649+instance FromJSON TemplateQueryKeyValuePairs where
1650+ parseJSON (Object o) = pure . TemplateQueryKeyValuePairs $ HM.mapMaybe getValue o
1651+ where getValue (String x) = Just x
1652+ getValue _ = Nothing
1653+ parseJSON _ = fail "error parsing TemplateQueryKeyValuePairs"
1654+
1655+data TemplateQueryInline =
1656+ TemplateQueryInline { inline :: Query
1657+ , params :: TemplateQueryKeyValuePairs
1658+ }
1659+ deriving (Eq, Read, Show, Generic, Typeable)
1660+
1661+instance ToJSON TemplateQueryInline where
1662+ toJSON TemplateQueryInline{..} = object [ "inline" .= inline
1663+ , "params" .= params
1664+ ]
1665+
1666+instance FromJSON TemplateQueryInline where
1667+ parseJSON = withObject "TemplateQueryInline" parse
1668+ where parse o = TemplateQueryInline
1669+ <$> o .: "inline"
1670+ <*> o .: "params"
1671+
1672+
1625data SearchResult a =
1673data SearchResult a =
1626 SearchResult { took :: Int
1674 SearchResult { took :: Int
1627 , timedOut :: Bool
1675 , timedOut :: Bool
1628 , shards :: ShardResult
1676 , shards :: ShardResult
1629 , searchHits :: SearchHits a
1677 , searchHits :: SearchHits a
1630 , aggregations :: Maybe AggregationResults
1678 , aggregations :: Maybe AggregationResults
1679+ , scrollId :: Maybe ScrollId
1680+ , suggest :: Maybe NamedSuggestionResponse -- ^ Only one Suggestion request / response per Search is supported.
1681+ }
1631− , scrollId :: Maybe ScrollId } deriving (Eq, Read, Show, Generic, Typeable)
1682+ deriving (Eq, Read, Show, Generic, Typeable)
1632
1683
1633newtype ScrollId = ScrollId Text deriving (Eq, Read, Show, Generic, Ord, ToJSON, FromJSON)
1684newtype ScrollId = ScrollId Text deriving (Eq, Read, Show, Generic, Ord, ToJSON, FromJSON)
1634
1685
@@ -2220,6 +2271,9 @@ instance ToJSON Query where
2220 toJSON QueryMatchNoneQuery =
2271 toJSON QueryMatchNoneQuery =
2221 object ["match_none" .= object []]
2272 object ["match_none" .= object []]
2222
2273
2274+ toJSON (QueryTemplateQueryInline templateQuery) =
2275+ object [ "template" .= templateQuery ]
2276+
2223instance FromJSON Query where
2277instance FromJSON Query where
2224 parseJSON v = withObject "Query" parse v
2278 parseJSON v = withObject "Query" parse v
2225 where parse o = termQuery `taggedWith` "term"
2279 where parse o = termQuery `taggedWith` "term"
@@ -2247,6 +2301,7 @@ instance FromJSON Query where
2247 <|> queryRangeQuery `taggedWith` "range"
2301 <|> queryRangeQuery `taggedWith` "range"
2248 <|> queryRegexpQuery `taggedWith` "regexp"
2302 <|> queryRegexpQuery `taggedWith` "regexp"
2249 <|> querySimpleQueryStringQuery `taggedWith` "simple_query_string"
2303 <|> querySimpleQueryStringQuery `taggedWith` "simple_query_string"
2304+ <|> queryTemplateQueryInline `taggedWith` "template"
2250 where taggedWith parser k = parser =<< o .: k
2305 where taggedWith parser k = parser =<< o .: k
2251 termQuery = fieldTagged $ \(FieldName fn) o ->
2306 termQuery = fieldTagged $ \(FieldName fn) o ->
2252 TermQuery <$> (Term fn <$> o .: "value") <*> o .:? "boost"
2307 TermQuery <$> (Term fn <$> o .: "value") <*> o .:? "boost"
@@ -2284,6 +2339,7 @@ instance FromJSON Query where
2284 queryRegexpQuery = pure . QueryRegexpQuery
2339 queryRegexpQuery = pure . QueryRegexpQuery
2285 querySimpleQueryStringQuery = pure . QuerySimpleQueryStringQuery
2340 querySimpleQueryStringQuery = pure . QuerySimpleQueryStringQuery
2286 -- queryExistsQuery o = QueryExistsQuery <$> o .: "field"
2341 -- queryExistsQuery o = QueryExistsQuery <$> o .: "field"
2342+ queryTemplateQueryInline = pure . QueryTemplateQueryInline
2287
2343
2288
2344
2289omitNulls :: [(Text, Value)] -> Value
2345omitNulls :: [(Text, Value)] -> Value
@@ -2810,7 +2866,7 @@ instance ToJSON MultiMatchQuery where
2810 , "query" .= query
2866 , "query" .= query
2811 , "operator" .= boolOp
2867 , "operator" .= boolOp
2812 , "zero_terms_query" .= ztQ
2868 , "zero_terms_query" .= ztQ
2813− , "tiebreaker" .= tb
2869+ , "tie_breaker" .= tb
2814 , "type" .= mmqt
2870 , "type" .= mmqt
2815 , "cutoff_frequency" .= cf
2871 , "cutoff_frequency" .= cf
2816 , "analyzer" .= analyzer
2872 , "analyzer" .= analyzer
@@ -2825,7 +2881,7 @@ instance FromJSON MultiMatchQuery where
2825 <*> o .: "query"
2881 <*> o .: "query"
2826 <*> o .: "operator"
2882 <*> o .: "operator"
2827 <*> o .: "zero_terms_query"
2883 <*> o .: "zero_terms_query"
2828− <*> o .:? "tiebreaker"
2884+ <*> o .:? "tie_breaker"
2829 <*> o .:? "type"
2885 <*> o .:? "type"
2830 <*> o .:? "cutoff_frequency"
2886 <*> o .:? "cutoff_frequency"
2831 <*> o .:? "analyzer"
2887 <*> o .:? "analyzer"
@@ -3212,7 +3268,7 @@ instance FromJSON SearchAliasRouting where
3212 where parse t = SearchAliasRouting <$> parseNEJSON (String <$> T.splitOn "," t)
3268 where parse t = SearchAliasRouting <$> parseNEJSON (String <$> T.splitOn "," t)
3213
3269
3214instance ToJSON Search where
3270instance ToJSON Search where
3215− toJSON (Search mquery sFilter sort searchAggs highlight sTrackSortScores sFrom sSize _ sFields sSource) =
3271+ toJSON (Search mquery sFilter sort searchAggs highlight sTrackSortScores sFrom sSize _ sFields sSource sSuggest) =
3216 omitNulls [ "query" .= query'
3272 omitNulls [ "query" .= query'
3217 , "sort" .= sort
3273 , "sort" .= sort
3218 , "aggregations" .= searchAggs
3274 , "aggregations" .= searchAggs
@@ -3221,7 +3277,8 @@ instance ToJSON Search where
3221 , "size" .= sSize
3277 , "size" .= sSize
3222 , "track_scores" .= sTrackSortScores
3278 , "track_scores" .= sTrackSortScores
3223 , "fields" .= sFields
3279 , "fields" .= sFields
3224− , "_source" .= sSource]
3280+ , "_source" .= sSource
3281+ , "suggest" .= sSuggest]
3225
3282
3226 where query' = case sFilter of
3283 where query' = case sFilter of
3227 Nothing -> mquery
3284 Nothing -> mquery
@@ -3574,7 +3631,8 @@ instance (FromJSON a) => FromJSON (SearchResult a) where
3574 v .: "_shards" <*>
3631 v .: "_shards" <*>
3575 v .: "hits" <*>
3632 v .: "hits" <*>
3576 v .:? "aggregations" <*>
3633 v .:? "aggregations" <*>
3577− v .:? "_scroll_id"
3634+ v .:? "_scroll_id" <*>
3635+ v .:? "suggest"
3578 parseJSON _ = empty
3636 parseJSON _ = empty
3579
3637
3580instance (FromJSON a) => FromJSON (SearchHits a) where
3638instance (FromJSON a) => FromJSON (SearchHits a) where
@@ -5055,3 +5113,178 @@ newtype MaybeNA a = MaybeNA { unMaybeNA :: Maybe a }
5055instance FromJSON a => FromJSON (MaybeNA a) where
5113instance FromJSON a => FromJSON (MaybeNA a) where
5056 parseJSON (String "NA") = pure $ MaybeNA Nothing
5114 parseJSON (String "NA") = pure $ MaybeNA Nothing
5057 parseJSON o = MaybeNA . Just <$> parseJSON o
5115 parseJSON o = MaybeNA . Just <$> parseJSON o
5116+
5117+data Suggest = Suggest { suggestText :: Text
5118+ , suggestName :: Text
5119+ , suggestType :: SuggestType
5120+ }
5121+ deriving (Show, Generic, Eq, Read)
5122+
5123+instance ToJSON Suggest where
5124+ toJSON Suggest{..} = object [ "text" .= suggestText
5125+ , suggestName .= suggestType
5126+ ]
5127+
5128+instance FromJSON Suggest where
5129+ parseJSON (Object o) = do
5130+ suggestText' <- o .: "text"
5131+ let dropTextList = HM.toList $ HM.filterWithKey (\x _ -> x /= "text") o
5132+ suggestName' <- case dropTextList of
5133+ [(x, _)] -> return x
5134+ _ -> fail "error parsing Suggest field name"
5135+ suggestType' <- o .: suggestName'
5136+ return $ Suggest suggestText' suggestName' suggestType'
5137+ parseJSON x = typeMismatch "Suggest" x
5138+
5139+data SuggestType = SuggestTypePhraseSuggester PhraseSuggester
5140+ deriving (Show, Generic, Eq, Read)
5141+
5142+instance ToJSON SuggestType where
5143+ toJSON (SuggestTypePhraseSuggester x) = object ["phrase" .= x]
5144+
5145+instance FromJSON SuggestType where
5146+ parseJSON = withObject "SuggestType" parse
5147+ where parse o = phraseSuggester `taggedWith` "phrase"
5148+ where taggedWith parser k = parser =<< o .: k
5149+ phraseSuggester = pure . SuggestTypePhraseSuggester
5150+
5151+data PhraseSuggester =
5152+ PhraseSuggester { phraseSuggesterField :: FieldName
5153+ , phraseSuggesterGramSize :: Maybe Int
5154+ , phraseSuggesterRealWordErrorLikelihood :: Maybe Int
5155+ , phraseSuggesterConfidence :: Maybe Int
5156+ , phraseSuggesterMaxErrors :: Maybe Int
5157+ , phraseSuggesterSeparator :: Maybe Text
5158+ , phraseSuggesterSize :: Maybe Size
5159+ , phraseSuggesterAnalyzer :: Maybe Analyzer
5160+ , phraseSuggesterShardSize :: Maybe Int
5161+ , phraseSuggesterHighlight :: Maybe PhraseSuggesterHighlighter
5162+ , phraseSuggesterCollate :: Maybe PhraseSuggesterCollate
5163+ }
5164+ deriving (Show, Generic, Eq, Read)
5165+
5166+instance ToJSON PhraseSuggester where
5167+ toJSON PhraseSuggester{..} = omitNulls [ "field" .= phraseSuggesterField
5168+ , "gram_size" .= phraseSuggesterGramSize
5169+ , "real_word_error_likelihood" .= phraseSuggesterRealWordErrorLikelihood
5170+ , "confidence" .= phraseSuggesterConfidence
5171+ , "max_errors" .= phraseSuggesterMaxErrors
5172+ , "separator" .= phraseSuggesterSeparator
5173+ , "size" .= phraseSuggesterSize
5174+ , "analyzer" .= phraseSuggesterAnalyzer
5175+ , "shard_size" .= phraseSuggesterShardSize
5176+ , "highlight" .= phraseSuggesterHighlight
5177+ , "collate" .= phraseSuggesterCollate
5178+ ]
5179+
5180+instance FromJSON PhraseSuggester where
5181+ parseJSON = withObject "PhraseSuggester" parse
5182+ where parse o = PhraseSuggester
5183+ <$> o .: "field"
5184+ <*> o .:? "gram_size"
5185+ <*> o .:? "real_word_error_likelihood"
5186+ <*> o .:? "confidence"
5187+ <*> o .:? "max_errors"
5188+ <*> o .:? "separator"
5189+ <*> o .:? "size"
5190+ <*> o .:? "analyzer"
5191+ <*> o .:? "shard_size"
5192+ <*> o .:? "highlight"
5193+ <*> o .:? "collate"
5194+
5195+mkPhraseSuggester :: FieldName -> PhraseSuggester
5196+mkPhraseSuggester fName =
5197+ PhraseSuggester fName Nothing Nothing Nothing Nothing Nothing Nothing
5198+ Nothing Nothing Nothing Nothing
5199+
5200+data PhraseSuggesterHighlighter =
5201+ PhraseSuggesterHighlighter { phraseSuggesterHighlighterPreTag :: Text
5202+ , phraseSuggesterHighlighterPostTag :: Text
5203+ }
5204+ deriving (Show, Generic, Eq, Read)
5205+
5206+instance ToJSON PhraseSuggesterHighlighter where
5207+ toJSON PhraseSuggesterHighlighter{..} =
5208+ object [ "pre_tag" .= phraseSuggesterHighlighterPreTag
5209+ , "post_tag" .= phraseSuggesterHighlighterPostTag
5210+ ]
5211+
5212+instance FromJSON PhraseSuggesterHighlighter where
5213+ parseJSON = withObject "PhraseSuggesterHighlighter" parse
5214+ where parse o = PhraseSuggesterHighlighter
5215+ <$> o .: "pre_tag"
5216+ <*> o .: "post_tag"
5217+
5218+data PhraseSuggesterCollate =
5219+ PhraseSuggesterCollate { phraseSuggesterCollateTemplateQuery :: TemplateQueryInline
5220+ , phraseSuggesterCollatePrune :: Bool
5221+ }
5222+ deriving (Show, Generic, Eq, Read)
5223+
5224+instance ToJSON PhraseSuggesterCollate where
5225+ toJSON PhraseSuggesterCollate{..} = object [ "query" .= object
5226+ [ "inline" .= (inline phraseSuggesterCollateTemplateQuery)
5227+ ]
5228+ , "params" .= (params phraseSuggesterCollateTemplateQuery)
5229+ , "prune" .= phraseSuggesterCollatePrune
5230+ ]
5231+
5232+instance FromJSON PhraseSuggesterCollate where
5233+ parseJSON (Object o) = do
5234+ query' <- o .: "query"
5235+ inline' <- query' .: "inline"
5236+ params' <- o .: "params"
5237+ prune' <- o .:? "prune" .!= False
5238+ return $ PhraseSuggesterCollate (TemplateQueryInline inline' params') prune'
5239+ parseJSON x = typeMismatch "PhraseSuggesterCollate" x
5240+
5241+mkPhraseSuggesterCollate :: TemplateQueryInline -> PhraseSuggesterCollate
5242+mkPhraseSuggesterCollate tQuery = PhraseSuggesterCollate tQuery False
5243+
5244+data SuggestOptions =
5245+ SuggestOptions { suggestOptionsText :: Text
5246+ , suggestOptionsScore :: Double
5247+ , suggestOptionsFreq :: Maybe Int
5248+ , suggestOptionsHighlighted :: Maybe Text
5249+ }
5250+ deriving (Eq, Read, Show)
5251+
5252+instance FromJSON SuggestOptions where
5253+ parseJSON = withObject "SuggestOptions" parse
5254+ where parse o = SuggestOptions
5255+ <$> o .: "text"
5256+ <*> o .: "score"
5257+ <*> o .:? "freq"
5258+ <*> o .:? "highlighted"
5259+
5260+data SuggestResponse =
5261+ SuggestResponse { suggestResponseText :: Text
5262+ , suggestResponseOffset :: Int
5263+ , suggestResponseLength :: Int
5264+ , suggestResponseOptions :: [SuggestOptions]
5265+ }
5266+ deriving (Eq, Read, Show)
5267+
5268+instance FromJSON SuggestResponse where
5269+ parseJSON = withObject "SuggestResponse" parse
5270+ where parse o = SuggestResponse
5271+ <$> o .: "text"
5272+ <*> o .: "offset"
5273+ <*> o .: "length"
5274+ <*> o .: "options"
5275+
5276+data NamedSuggestionResponse =
5277+ NamedSuggestionResponse { nsrName :: Text
5278+ , nsrResponses :: [SuggestResponse]
5279+ }
5280+ deriving (Eq, Read, Show)
5281+
5282+instance FromJSON NamedSuggestionResponse where
5283+ parseJSON (Object o) = do
5284+ suggestionName' <- case HM.toList o of
5285+ [(x, _)] -> return x
5286+ _ -> fail "error parsing NamedSuggestionResponse name"
5287+ suggestionResponses' <- o .: suggestionName'
5288+ return $ NamedSuggestionResponse suggestionName' suggestionResponses'
5289+
5290+ parseJSON x = typeMismatch "NamedSuggestionResponse" x
stack-7.8.yaml+1
@@ -18,4 +18,5 @@ extra-deps:
18- uri-bytestring-0.1.9
18- uri-bytestring-0.1.9
19- void-0.7.1
19- void-0.7.1
20- generics-sop-0.2.2.0
20- generics-sop-0.2.2.0
21+- unordered-containers-0.2.6.0
21resolver: lts-2.18
22resolver: lts-2.18
tests/V1/tests.hs+66
@@ -595,6 +595,15 @@ instance (ApproxEq l, ApproxEq r) => ApproxEq (Either l r) where
595instance ApproxEq NodeAttrFilter
595instance ApproxEq NodeAttrFilter
596instance ApproxEq NodeAttrName
596instance ApproxEq NodeAttrName
597instance ApproxEq BuildHash
597instance ApproxEq BuildHash
598+instance ApproxEq TemplateQueryKeyValuePairs where
599+ (=~) = (==)
600+instance ApproxEq TemplateQueryInline
601+instance ApproxEq Size
602+instance ApproxEq PhraseSuggesterHighlighter
603+instance ApproxEq PhraseSuggesterCollate
604+instance ApproxEq PhraseSuggester
605+instance ApproxEq SuggestType
606+instance ApproxEq Suggest
598
607
599-- | Due to the way nodeattrfilters get serialized here, they may come
608-- | Due to the way nodeattrfilters get serialized here, they may come
600-- out in a different order, but they are morally equivalent
609-- out in a different order, but they are morally equivalent
@@ -746,6 +755,7 @@ instance Arbitrary Query where
746 , QuerySimpleQueryStringQuery <$> arbitrary
755 , QuerySimpleQueryStringQuery <$> arbitrary
747 , QueryRangeQuery <$> arbitrary
756 , QueryRangeQuery <$> arbitrary
748 , QueryRegexpQuery <$> arbitrary
757 , QueryRegexpQuery <$> arbitrary
758+ , QueryTemplateQueryInline <$> arbitrary
749 ]
759 ]
750 shrink = genericShrink
760 shrink = genericShrink
751
761
@@ -798,6 +808,10 @@ instance Arbitrary VersionNumber where
798 where
808 where
799 mk versions = VersionNumber (Vers.Version versions [])
809 mk versions = VersionNumber (Vers.Version versions [])
800
810
811+instance Arbitrary TemplateQueryKeyValuePairs where
812+ arbitrary = TemplateQueryKeyValuePairs . HM.fromList <$> arbitrary
813+ shrink (TemplateQueryKeyValuePairs x) = map (TemplateQueryKeyValuePairs . HM.fromList) . shrink $ HM.toList x
814+
801instance Arbitrary IndexName where arbitrary = sopArbitrary; shrink = genericShrink
815instance Arbitrary IndexName where arbitrary = sopArbitrary; shrink = genericShrink
802instance Arbitrary MappingName where arbitrary = sopArbitrary; shrink = genericShrink
816instance Arbitrary MappingName where arbitrary = sopArbitrary; shrink = genericShrink
803instance Arbitrary DocId where arbitrary = sopArbitrary; shrink = genericShrink
817instance Arbitrary DocId where arbitrary = sopArbitrary; shrink = genericShrink
@@ -913,6 +927,13 @@ instance Arbitrary FSType where arbitrary = sopArbitrary; shrink = genericShrink
913instance Arbitrary CompoundFormat where arbitrary = sopArbitrary; shrink = genericShrink
927instance Arbitrary CompoundFormat where arbitrary = sopArbitrary; shrink = genericShrink
914instance Arbitrary FsSnapshotRepo where arbitrary = sopArbitrary; shrink = genericShrink
928instance Arbitrary FsSnapshotRepo where arbitrary = sopArbitrary; shrink = genericShrink
915instance Arbitrary SnapshotRepoName where arbitrary = sopArbitrary; shrink = genericShrink
929instance Arbitrary SnapshotRepoName where arbitrary = sopArbitrary; shrink = genericShrink
930+instance Arbitrary TemplateQueryInline where arbitrary = sopArbitrary; shrink = genericShrink
931+instance Arbitrary PhraseSuggesterCollate where arbitrary = sopArbitrary; shrink = genericShrink
932+instance Arbitrary PhraseSuggesterHighlighter where arbitrary = sopArbitrary; shrink = genericShrink
933+instance Arbitrary Size where arbitrary = sopArbitrary; shrink = genericShrink
934+instance Arbitrary PhraseSuggester where arbitrary = sopArbitrary; shrink = genericShrink
935+instance Arbitrary SuggestType where arbitrary = sopArbitrary; shrink = genericShrink
936+instance Arbitrary Suggest where arbitrary = sopArbitrary; shrink = genericShrink
916
937
917newtype UpdatableIndexSetting' = UpdatableIndexSetting' UpdatableIndexSetting
938newtype UpdatableIndexSetting' = UpdatableIndexSetting' UpdatableIndexSetting
918 deriving (Show, Eq, ToJSON, FromJSON, ApproxEq, Typeable)
939 deriving (Show, Eq, ToJSON, FromJSON, ApproxEq, Typeable)
@@ -1091,6 +1112,17 @@ main = hspec $ do
1091 liftIO $
1112 liftIO $
1092 myTweet `shouldBe` Right exampleTweet
1113 myTweet `shouldBe` Right exampleTweet
1093
1114
1115+ it "returns document for multi-match query with a custom tiebreaker" $ withTestEnv $ do
1116+ _ <- insertData
1117+ let tiebreaker = Just $ Tiebreaker 0.3
1118+ flds = [FieldName "user", FieldName "message"]
1119+ multiQuery' = mkMultiMatchQuery flds (QueryString "bitemyapp")
1120+ query = QueryMultiMatchQuery $ multiQuery' { multiMatchQueryTiebreaker = tiebreaker }
1121+ search = mkSearch (Just query) Nothing
1122+ myTweet <- searchTweet search
1123+ liftIO $
1124+ myTweet `shouldBe` Right exampleTweet
1125+
1094 it "returns document for bool query" $ withTestEnv $ do
1126 it "returns document for bool query" $ withTestEnv $ do
1095 _ <- insertData
1127 _ <- insertData
1096 let innerQuery = QueryMatchQuery $
1128 let innerQuery = QueryMatchQuery $
@@ -1124,6 +1156,21 @@ main = hspec $ do
1124 liftIO $
1156 liftIO $
1125 myTweet `shouldBe` Right exampleTweet
1157 myTweet `shouldBe` Right exampleTweet
1126
1158
1159+ it "returns document for for inline template query" $ withTestEnv $ do
1160+ _ <- insertData
1161+ let innerQuery = QueryMatchQuery $
1162+ mkMatchQuery (FieldName "{{userKey}}")
1163+ (QueryString "{{bitemyappKey}}")
1164+ templateParams = TemplateQueryKeyValuePairs $ HM.fromList
1165+ [ ("userKey", "user")
1166+ , ("bitemyappKey", "bitemyapp")
1167+ ]
1168+ templateQuery = QueryTemplateQueryInline $
1169+ TemplateQueryInline innerQuery templateParams
1170+ search = mkSearch (Just templateQuery) Nothing
1171+ myTweet <- searchTweet search
1172+ liftIO $ myTweet `shouldBe` Right exampleTweet
1173+
1127
1174
1128 describe "sorting" $ do
1175 describe "sorting" $ do
1129 it "returns documents in the right order" $ withTestEnv $ do
1176 it "returns documents in the right order" $ withTestEnv $ do
@@ -1133,6 +1180,7 @@ main = hspec $ do
1133 let search = Search Nothing
1180 let search = Search Nothing
1134 (Just IdentityFilter) (Just [sortSpec]) Nothing Nothing
1181 (Just IdentityFilter) (Just [sortSpec]) Nothing Nothing
1135 False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing
1182 False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing
1183+ Nothing
1136 result <- searchTweets search
1184 result <- searchTweets search
1137 let myTweet = grabFirst result
1185 let myTweet = grabFirst result
1138 liftIO $
1186 liftIO $
@@ -1761,6 +1809,22 @@ main = hspec $ do
1761 resp <- optimizeIndex (IndexList (testIndex :| [])) defaultIndexOptimizationSettings
1809 resp <- optimizeIndex (IndexList (testIndex :| [])) defaultIndexOptimizationSettings
1762 liftIO $ validateStatus resp 200
1810 liftIO $ validateStatus resp 200
1763
1811
1812+ describe "Suggest" $ do
1813+ it "returns a search suggestion using the phrase suggester" $ withTestEnv $ do
1814+ _ <- insertData
1815+ let {- query = QueryMatchNoneQuery
1816+ query = TermQuery (Term "user" "bitemyapp") Nothing -}
1817+ let phraseSuggester = mkPhraseSuggester (FieldName "message")
1818+ namedSuggester = Suggest "Use haskel" "suggest_name" (SuggestTypePhraseSuggester phraseSuggester)
1819+ search' = mkSearch Nothing Nothing
1820+ search = search' { suggestBody = Just namedSuggester }
1821+ expectedText = Just "use haskell"
1822+ resp <- searchByIndex testIndex search
1823+ parsed <- parseEsResponse resp :: BH IO (Either EsError (SearchResult Tweet))
1824+ case parsed of
1825+ Left e -> liftIO $ expectationFailure ("Expected an search suggestion but got " <> show e)
1826+ Right sr -> liftIO $ (suggestOptionsText . head . suggestResponseOptions . head . nsrResponses <$> suggest sr) `shouldBe` expectedText
1827+
1764 describe "JSON instances" $ do
1828 describe "JSON instances" $ do
1765 propJSON (Proxy :: Proxy Version)
1829 propJSON (Proxy :: Proxy Version)
1766 propJSON (Proxy :: Proxy IndexName)
1830 propJSON (Proxy :: Proxy IndexName)
@@ -1864,6 +1928,8 @@ main = hspec $ do
1864 propJSON (Proxy :: Proxy InitialShardCount)
1928 propJSON (Proxy :: Proxy InitialShardCount)
1865 propJSON (Proxy :: Proxy FSType)
1929 propJSON (Proxy :: Proxy FSType)
1866 propJSON (Proxy :: Proxy CompoundFormat)
1930 propJSON (Proxy :: Proxy CompoundFormat)
1931+ propJSON (Proxy :: Proxy TemplateQueryInline)
1932+ propJSON (Proxy :: Proxy Suggest)
1867
1933
1868-- Temporary solution for lacking of generic derivation of Arbitrary
1934-- Temporary solution for lacking of generic derivation of Arbitrary
1869-- We use generics-sop, as it's much more concise than directly using GHC.Generics
1935-- We use generics-sop, as it's much more concise than directly using GHC.Generics
tests/V5/tests.hs+65
@@ -607,6 +607,15 @@ instance (ApproxEq l, Show l, ApproxEq r, Show r) => ApproxEq (Either l r) where
607instance ApproxEq NodeAttrFilter
607instance ApproxEq NodeAttrFilter
608instance ApproxEq NodeAttrName
608instance ApproxEq NodeAttrName
609instance ApproxEq BuildHash
609instance ApproxEq BuildHash
610+instance ApproxEq TemplateQueryKeyValuePairs where
611+ (=~) = (==)
612+instance ApproxEq TemplateQueryInline
613+instance ApproxEq Size
614+instance ApproxEq PhraseSuggesterHighlighter
615+instance ApproxEq PhraseSuggesterCollate
616+instance ApproxEq PhraseSuggester
617+instance ApproxEq SuggestType
618+instance ApproxEq Suggest
610
619
611-- | Due to the way nodeattrfilters get serialized here, they may come
620-- | Due to the way nodeattrfilters get serialized here, they may come
612-- out in a different order, but they are morally equivalent
621-- out in a different order, but they are morally equivalent
@@ -756,6 +765,7 @@ instance Arbitrary Query where
756 , QuerySimpleQueryStringQuery <$> arbitrary
765 , QuerySimpleQueryStringQuery <$> arbitrary
757 , QueryRangeQuery <$> arbitrary
766 , QueryRangeQuery <$> arbitrary
758 , QueryRegexpQuery <$> arbitrary
767 , QueryRegexpQuery <$> arbitrary
768+ , QueryTemplateQueryInline <$> arbitrary
759 ]
769 ]
760 shrink = genericShrink
770 shrink = genericShrink
761
771
@@ -791,6 +801,10 @@ instance Arbitrary VersionNumber where
791 where
801 where
792 mk versions = VersionNumber (Vers.Version versions [])
802 mk versions = VersionNumber (Vers.Version versions [])
793
803
804+instance Arbitrary TemplateQueryKeyValuePairs where
805+ arbitrary = TemplateQueryKeyValuePairs . HM.fromList <$> arbitrary
806+ shrink (TemplateQueryKeyValuePairs x) = map (TemplateQueryKeyValuePairs . HM.fromList) . shrink $ HM.toList x
807+
794instance Arbitrary IndexName where arbitrary = sopArbitrary; shrink = genericShrink
808instance Arbitrary IndexName where arbitrary = sopArbitrary; shrink = genericShrink
795instance Arbitrary MappingName where arbitrary = sopArbitrary; shrink = genericShrink
809instance Arbitrary MappingName where arbitrary = sopArbitrary; shrink = genericShrink
796instance Arbitrary DocId where arbitrary = sopArbitrary; shrink = genericShrink
810instance Arbitrary DocId where arbitrary = sopArbitrary; shrink = genericShrink
@@ -898,6 +912,13 @@ instance Arbitrary FSType where arbitrary = sopArbitrary; shrink = genericShrink
898instance Arbitrary CompoundFormat where arbitrary = sopArbitrary; shrink = genericShrink
912instance Arbitrary CompoundFormat where arbitrary = sopArbitrary; shrink = genericShrink
899instance Arbitrary FsSnapshotRepo where arbitrary = sopArbitrary; shrink = genericShrink
913instance Arbitrary FsSnapshotRepo where arbitrary = sopArbitrary; shrink = genericShrink
900instance Arbitrary SnapshotRepoName where arbitrary = sopArbitrary; shrink = genericShrink
914instance Arbitrary SnapshotRepoName where arbitrary = sopArbitrary; shrink = genericShrink
915+instance Arbitrary TemplateQueryInline where arbitrary = sopArbitrary; shrink = genericShrink
916+instance Arbitrary PhraseSuggesterCollate where arbitrary = sopArbitrary; shrink = genericShrink
917+instance Arbitrary PhraseSuggesterHighlighter where arbitrary = sopArbitrary; shrink = genericShrink
918+instance Arbitrary Size where arbitrary = sopArbitrary; shrink = genericShrink
919+instance Arbitrary PhraseSuggester where arbitrary = sopArbitrary; shrink = genericShrink
920+instance Arbitrary SuggestType where arbitrary = sopArbitrary; shrink = genericShrink
921+instance Arbitrary Suggest where arbitrary = sopArbitrary; shrink = genericShrink
901
922
902newtype UpdatableIndexSetting' = UpdatableIndexSetting' UpdatableIndexSetting
923newtype UpdatableIndexSetting' = UpdatableIndexSetting' UpdatableIndexSetting
903 deriving (Show, Eq, ToJSON, FromJSON, ApproxEq, Typeable)
924 deriving (Show, Eq, ToJSON, FromJSON, ApproxEq, Typeable)
@@ -1066,6 +1087,17 @@ main = hspec $ do
1066 liftIO $
1087 liftIO $
1067 myTweet `shouldBe` Right exampleTweet
1088 myTweet `shouldBe` Right exampleTweet
1068
1089
1090+ it "returns document for multi-match query with a custom tiebreaker" $ withTestEnv $ do
1091+ _ <- insertData
1092+ let tiebreaker = Just $ Tiebreaker 0.3
1093+ flds = [FieldName "user", FieldName "message"]
1094+ multiQuery' = mkMultiMatchQuery flds (QueryString "bitemyapp")
1095+ query = QueryMultiMatchQuery $ multiQuery' { multiMatchQueryTiebreaker = tiebreaker }
1096+ search = mkSearch (Just query) Nothing
1097+ myTweet <- searchTweet search
1098+ liftIO $
1099+ myTweet `shouldBe` Right exampleTweet
1100+
1069 it "returns document for bool query" $ withTestEnv $ do
1101 it "returns document for bool query" $ withTestEnv $ do
1070 _ <- insertData
1102 _ <- insertData
1071 let innerQuery = QueryMatchQuery $
1103 let innerQuery = QueryMatchQuery $
@@ -1099,6 +1131,21 @@ main = hspec $ do
1099 liftIO $
1131 liftIO $
1100 myTweet `shouldBe` Right exampleTweet
1132 myTweet `shouldBe` Right exampleTweet
1101
1133
1134+ it "returns document for for inline template query" $ withTestEnv $ do
1135+ _ <- insertData
1136+ let innerQuery = QueryMatchQuery $
1137+ mkMatchQuery (FieldName "{{userKey}}")
1138+ (QueryString "{{bitemyappKey}}")
1139+ templateParams = TemplateQueryKeyValuePairs $ HM.fromList
1140+ [ ("userKey", "user")
1141+ , ("bitemyappKey", "bitemyapp")
1142+ ]
1143+ templateQuery = QueryTemplateQueryInline $
1144+ TemplateQueryInline innerQuery templateParams
1145+ search = mkSearch (Just templateQuery) Nothing
1146+ myTweet <- searchTweet search
1147+ liftIO $ myTweet `shouldBe` Right exampleTweet
1148+
1102
1149
1103 describe "sorting" $ do
1150 describe "sorting" $ do
1104 it "returns documents in the right order" $ withTestEnv $ do
1151 it "returns documents in the right order" $ withTestEnv $ do
@@ -1108,6 +1155,7 @@ main = hspec $ do
1108 let search = Search Nothing
1155 let search = Search Nothing
1109 Nothing (Just [sortSpec]) Nothing Nothing
1156 Nothing (Just [sortSpec]) Nothing Nothing
1110 False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing
1157 False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing
1158+ Nothing
1111 result <- searchTweets search
1159 result <- searchTweets search
1112 let myTweet = grabFirst result
1160 let myTweet = grabFirst result
1113 liftIO $
1161 liftIO $
@@ -1546,6 +1594,21 @@ main = hspec $ do
1546 resp <- forceMergeIndex (IndexList (testIndex :| [])) defaultForceMergeIndexSettings
1594 resp <- forceMergeIndex (IndexList (testIndex :| [])) defaultForceMergeIndexSettings
1547 liftIO $ validateStatus resp 200
1595 liftIO $ validateStatus resp 200
1548
1596
1597+ describe "Suggest" $ do
1598+ it "returns a search suggestion using the phrase suggester" $ withTestEnv $ do
1599+ _ <- insertData
1600+ let query = QueryMatchNoneQuery
1601+ phraseSuggester = mkPhraseSuggester (FieldName "message")
1602+ namedSuggester = Suggest "Use haskel" "suggest_name" (SuggestTypePhraseSuggester phraseSuggester)
1603+ search' = mkSearch (Just query) Nothing
1604+ search = search' { suggestBody = Just namedSuggester }
1605+ expectedText = Just "use haskell"
1606+ resp <- searchByIndex testIndex search
1607+ parsed <- parseEsResponse resp :: BH IO (Either EsError (SearchResult Tweet))
1608+ case parsed of
1609+ Left e -> liftIO $ expectationFailure ("Expected an search suggestion but got " <> show e)
1610+ Right sr -> liftIO $ (suggestOptionsText . head . suggestResponseOptions . head . nsrResponses <$> suggest sr) `shouldBe` expectedText
1611+
1549 describe "JSON instances" $ do
1612 describe "JSON instances" $ do
1550 propJSON (Proxy :: Proxy Version)
1613 propJSON (Proxy :: Proxy Version)
1551 propJSON (Proxy :: Proxy IndexName)
1614 propJSON (Proxy :: Proxy IndexName)
@@ -1648,6 +1711,8 @@ main = hspec $ do
1648 propJSON (Proxy :: Proxy InitialShardCount)
1711 propJSON (Proxy :: Proxy InitialShardCount)
1649 propJSON (Proxy :: Proxy FSType)
1712 propJSON (Proxy :: Proxy FSType)
1650 propJSON (Proxy :: Proxy CompoundFormat)
1713 propJSON (Proxy :: Proxy CompoundFormat)
1714+ propJSON (Proxy :: Proxy TemplateQueryInline)
1715+ propJSON (Proxy :: Proxy Suggest)
1651
1716
1652-- Temporary solution for lacking of generic derivation of Arbitrary
1717-- Temporary solution for lacking of generic derivation of Arbitrary
1653-- We use generics-sop, as it's much more concise than directly using GHC.Generics
1718-- We use generics-sop, as it's much more concise than directly using GHC.Generics