git.iko.soy/typeable/bloodhound
on master help sign in
range filters seem to be behaving themselves
d42111cChris Allen
Database/Bloodhound/Client.hs+91−1
@@ -38,6 +38,13 @@ module Database.Bloodhound.Client
38 , DistanceRange(..)
38 , DistanceRange(..)
39 , OptimizeBbox(..)
39 , OptimizeBbox(..)
40 , LatLon(..)
40 , LatLon(..)
41+ , Range(..)
42+ , HalfRange(..)
43+ , RangeExecution(..)
44+ , LessThan(..)
45+ , LessThanEq(..)
46+ , GreaterThan(..)
47+ , GreaterThanEq(..)
41 )
48 )
42 where
49 where
43
50
@@ -366,8 +373,13 @@ type FieldName = Text
366type Cache = Bool -- caching on/off
373type Cache = Bool -- caching on/off
367defaultCache = False
374defaultCache = False
368
375
376+type Existence = Bool
377+type NullValue = Bool
378+type PrefixValue = Text
379+
369data Filter = AndFilter [Filter] Cache
380data Filter = AndFilter [Filter] Cache
370− | OrFilter [Filter] Cache
381+ | OrFilter [Filter] Cache
382+ | NotFilter Filter Cache
371 | IdentityFilter
383 | IdentityFilter
372 | BoolFilter BoolMatch
384 | BoolFilter BoolMatch
373 | ExistsFilter FieldName -- always cached
385 | ExistsFilter FieldName -- always cached
@@ -376,6 +388,10 @@ data Filter = AndFilter [Filter] Cache
376 | GeoDistanceRangeFilter GeoPoint DistanceRange
388 | GeoDistanceRangeFilter GeoPoint DistanceRange
377 | GeoPolygonFilter FieldName [LatLon]
389 | GeoPolygonFilter FieldName [LatLon]
378 | IdsFilter MappingName [DocumentID]
390 | IdsFilter MappingName [DocumentID]
391+ | LimitFilter Int
392+ | MissingFilter FieldName Existence NullValue
393+ | PrefixFilter FieldName PrefixValue Cache
394+ | RangeFilter FieldName (Either HalfRange Range) RangeExecution Cache
379 deriving (Eq, Show)
395 deriving (Eq, Show)
380
396
381class Monoid a => Seminearring a where
397class Monoid a => Seminearring a where
@@ -403,6 +419,11 @@ instance ToJSON Filter where
403 object ["or" .= fmap toJSON filters
419 object ["or" .= fmap toJSON filters
404 , "_cache" .= cache]
420 , "_cache" .= cache]
405
421
422+ toJSON (NotFilter filter cache) =
423+ object ["not" .=
424+ object ["filter" .= toJSON filter
425+ , "_cache" .= cache]]
426+
406 toJSON (IdentityFilter) =
427 toJSON (IdentityFilter) =
407 object ["match_all" .= object []]
428 object ["match_all" .= object []]
408
429
@@ -443,6 +464,39 @@ instance ToJSON Filter where
443 object ["type" .= mappingName
464 object ["type" .= mappingName
444 , "values" .= fmap T.pack values]]
465 , "values" .= fmap T.pack values]]
445
466
467+ toJSON (LimitFilter limit) =
468+ object ["limit" .= object ["value" .= limit]]
469+
470+ toJSON (MissingFilter fieldName existence nullValue) =
471+ object ["missing" .=
472+ object ["field" .= fieldName
473+ , "existence" .= existence
474+ , "null_value" .= nullValue]]
475+
476+ toJSON (PrefixFilter fieldName fieldValue cache) =
477+ object ["prefix" .=
478+ object [fieldName .= fieldValue
479+ , "_cache" .= cache]]
480+
481+ toJSON (RangeFilter fieldName (Left halfRange) rangeExecution cache) =
482+ object ["range" .=
483+ object [fieldName .=
484+ object [key .= val]
485+ , "execution" .= toJSON rangeExecution
486+ , "_cache" .= cache]]
487+ where
488+ (key, val) = halfRangeToKV halfRange
489+
490+ toJSON (RangeFilter fieldName (Right range) rangeExecution cache) =
491+ object ["range" .=
492+ object [fieldName .=
493+ object [lessKey .= lessVal
494+ , greaterKey .= greaterVal]
495+ , "execution" .= toJSON rangeExecution
496+ , "_cache" .= cache]]
497+ where
498+ (lessKey, lessVal, greaterKey, greaterVal) = rangeToKV range
499+
446instance ToJSON GeoPoint where
500instance ToJSON GeoPoint where
447 toJSON (GeoPoint geoField latLon) =
501 toJSON (GeoPoint geoField latLon) =
448 object [geoField .= toJSON latLon]
502 object [geoField .= toJSON latLon]
@@ -496,6 +550,42 @@ instance ToJSON LatLon where
496 object ["lat" .= lat
550 object ["lat" .= lat
497 , "lon" .= lon]
551 , "lon" .= lon]
498
552
553+-- lt, lte | gt, gte
554+newtype LessThan = LessThan Double deriving (Eq, Show)
555+newtype LessThanEq = LessThanEq Double deriving (Eq, Show)
556+newtype GreaterThan = GreaterThan Double deriving (Eq, Show)
557+newtype GreaterThanEq = GreaterThanEq Double deriving (Eq, Show)
558+
559+data HalfRange = HalfRangeLt LessThan
560+ | HalfRangeLte LessThanEq
561+ | HalfRangeGt GreaterThan
562+ | HalfRangeGte GreaterThanEq deriving (Eq, Show)
563+
564+data Range = RangeLtGt LessThan GreaterThan
565+ | RangeLtGte LessThan GreaterThanEq
566+ | RangeLteGt LessThanEq GreaterThan
567+ | RangeLteGte LessThanEq GreaterThanEq deriving (Eq, Show)
568+
569+halfRangeToKV :: HalfRange -> (Text, Double)
570+halfRangeToKV (HalfRangeLt (LessThan n)) = ("lt", n)
571+halfRangeToKV (HalfRangeLte (LessThanEq n)) = ("lte", n)
572+halfRangeToKV (HalfRangeGt (GreaterThan n)) = ("gt", n)
573+halfRangeToKV (HalfRangeGte (GreaterThanEq n)) = ("gte", n)
574+
575+rangeToKV :: Range -> (Text, Double, Text, Double)
576+rangeToKV (RangeLtGt (LessThan m) (GreaterThan n)) = ("lt", m, "gt", n)
577+rangeToKV (RangeLtGte (LessThan m) (GreaterThanEq n)) = ("lt", m, "gte", n)
578+rangeToKV (RangeLteGt (LessThanEq m) (GreaterThan n)) = ("lte", m, "gt", n)
579+rangeToKV (RangeLteGte (LessThanEq m) (GreaterThanEq n)) = ("lte", m, "gte", n)
580+
581+data RangeExecution = RangeExecutionIndex
582+ | RangeExecutionFielddata deriving (Eq, Show)
583+
584+-- index for smaller ranges, fielddata for longer ranges
585+instance ToJSON RangeExecution where
586+ toJSON RangeExecutionIndex = "index"
587+ toJSON RangeExecutionFielddata = "fielddata"
588+
499data Term = Term { termField :: Text
589data Term = Term { termField :: Text
500 , termValue :: Text } deriving (Eq, Show)
590 , termValue :: Text } deriving (Eq, Show)
501
591
README.org+12
@@ -4,6 +4,10 @@
4
4
5Elasticsearch client and query DSL for Haskell
5Elasticsearch client and query DSL for Haskell
6
6
7+** Examples
8+
9+nope.jpg
10+
7** Possible future functionality
11** Possible future functionality
8
12
9*** GeoShapeFilter
13*** GeoShapeFilter
@@ -22,6 +26,14 @@ http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-
22
26
23http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-has-parent-filter.html
27http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-has-parent-filter.html
24
28
29+*** Indices Filter
30+
31+http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-indices-filter.html
32+
33+*** Query Filter
34+
35+http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-query-filter.html
36+
25*** Runtime checking for cycles in data structures
37*** Runtime checking for cycles in data structures
26
38
27check for n > 1 occurrences in DFS:
39check for n > 1 occurrences in DFS:
tests/tests.hs+11
@@ -32,6 +32,7 @@ data Location = Location { lat :: Double
32data Tweet = Tweet { user :: Text
32data Tweet = Tweet { user :: Text
33 , postDate :: UTCTime
33 , postDate :: UTCTime
34 , message :: Text
34 , message :: Text
35+ , age :: Int
35 , location :: Location }
36 , location :: Location }
36 deriving (Eq, Generic, Show)
37 deriving (Eq, Generic, Show)
37
38
@@ -53,6 +54,7 @@ exampleTweet = Tweet { user = "bitemyapp"
53 (ModifiedJulianDay 55000)
54 (ModifiedJulianDay 55000)
54 (secondsToDiffTime 10)
55 (secondsToDiffTime 10)
55 , message = "Use haskell!"
56 , message = "Use haskell!"
57+ , age = 10000
56 , location = Location 40.12 (-71.34) }
58 , location = Location 40.12 (-71.34) }
57
59
58insertData :: IO ()
60insertData :: IO ()
@@ -185,3 +187,12 @@ main = hspec $ do
185 let search = Search Nothing (Just filter)
187 let search = Search Nothing (Just filter)
186 myTweet <- searchTweet search
188 myTweet <- searchTweet search
187 myTweet `shouldBe` Right exampleTweet
189 myTweet `shouldBe` Right exampleTweet
190+
191+ it "returns document for range filter" $ do
192+ _ <- insertData
193+ let filter = RangeFilter "age"
194+ (Right (RangeLtGt (LessThan 100000.0) (GreaterThan 1000.0)))
195+ RangeExecutionIndex False
196+ let search = Search Nothing (Just filter)
197+ myTweet <- searchTweet search
198+ myTweet `shouldBe` Right exampleTweet