range filters seem to be behaving themselves

This commit is contained in:
Chris Allen 2014-04-11 00:48:29 -05:00
parent 631b8631e6
commit d42111ce5a
3 changed files with 114 additions and 1 deletions

View File

@ -38,6 +38,13 @@ module Database.Bloodhound.Client
, DistanceRange(..)
, OptimizeBbox(..)
, LatLon(..)
, Range(..)
, HalfRange(..)
, RangeExecution(..)
, LessThan(..)
, LessThanEq(..)
, GreaterThan(..)
, GreaterThanEq(..)
)
where
@ -366,8 +373,13 @@ type FieldName = Text
type Cache = Bool -- caching on/off
defaultCache = False
type Existence = Bool
type NullValue = Bool
type PrefixValue = Text
data Filter = AndFilter [Filter] Cache
| OrFilter [Filter] Cache
| OrFilter [Filter] Cache
| NotFilter Filter Cache
| IdentityFilter
| BoolFilter BoolMatch
| ExistsFilter FieldName -- always cached
@ -376,6 +388,10 @@ data Filter = AndFilter [Filter] Cache
| GeoDistanceRangeFilter GeoPoint DistanceRange
| GeoPolygonFilter FieldName [LatLon]
| IdsFilter MappingName [DocumentID]
| LimitFilter Int
| MissingFilter FieldName Existence NullValue
| PrefixFilter FieldName PrefixValue Cache
| RangeFilter FieldName (Either HalfRange Range) RangeExecution Cache
deriving (Eq, Show)
class Monoid a => Seminearring a where
@ -403,6 +419,11 @@ instance ToJSON Filter where
object ["or" .= fmap toJSON filters
, "_cache" .= cache]
toJSON (NotFilter filter cache) =
object ["not" .=
object ["filter" .= toJSON filter
, "_cache" .= cache]]
toJSON (IdentityFilter) =
object ["match_all" .= object []]
@ -443,6 +464,39 @@ instance ToJSON Filter where
object ["type" .= mappingName
, "values" .= fmap T.pack values]]
toJSON (LimitFilter limit) =
object ["limit" .= object ["value" .= limit]]
toJSON (MissingFilter fieldName existence nullValue) =
object ["missing" .=
object ["field" .= fieldName
, "existence" .= existence
, "null_value" .= nullValue]]
toJSON (PrefixFilter fieldName fieldValue cache) =
object ["prefix" .=
object [fieldName .= fieldValue
, "_cache" .= cache]]
toJSON (RangeFilter fieldName (Left halfRange) rangeExecution cache) =
object ["range" .=
object [fieldName .=
object [key .= val]
, "execution" .= toJSON rangeExecution
, "_cache" .= cache]]
where
(key, val) = halfRangeToKV halfRange
toJSON (RangeFilter fieldName (Right range) rangeExecution cache) =
object ["range" .=
object [fieldName .=
object [lessKey .= lessVal
, greaterKey .= greaterVal]
, "execution" .= toJSON rangeExecution
, "_cache" .= cache]]
where
(lessKey, lessVal, greaterKey, greaterVal) = rangeToKV range
instance ToJSON GeoPoint where
toJSON (GeoPoint geoField latLon) =
object [geoField .= toJSON latLon]
@ -496,6 +550,42 @@ instance ToJSON LatLon where
object ["lat" .= lat
, "lon" .= lon]
-- lt, lte | gt, gte
newtype LessThan = LessThan Double deriving (Eq, Show)
newtype LessThanEq = LessThanEq Double deriving (Eq, Show)
newtype GreaterThan = GreaterThan Double deriving (Eq, Show)
newtype GreaterThanEq = GreaterThanEq Double deriving (Eq, Show)
data HalfRange = HalfRangeLt LessThan
| HalfRangeLte LessThanEq
| HalfRangeGt GreaterThan
| HalfRangeGte GreaterThanEq deriving (Eq, Show)
data Range = RangeLtGt LessThan GreaterThan
| RangeLtGte LessThan GreaterThanEq
| RangeLteGt LessThanEq GreaterThan
| RangeLteGte LessThanEq GreaterThanEq deriving (Eq, Show)
halfRangeToKV :: HalfRange -> (Text, Double)
halfRangeToKV (HalfRangeLt (LessThan n)) = ("lt", n)
halfRangeToKV (HalfRangeLte (LessThanEq n)) = ("lte", n)
halfRangeToKV (HalfRangeGt (GreaterThan n)) = ("gt", n)
halfRangeToKV (HalfRangeGte (GreaterThanEq n)) = ("gte", n)
rangeToKV :: Range -> (Text, Double, Text, Double)
rangeToKV (RangeLtGt (LessThan m) (GreaterThan n)) = ("lt", m, "gt", n)
rangeToKV (RangeLtGte (LessThan m) (GreaterThanEq n)) = ("lt", m, "gte", n)
rangeToKV (RangeLteGt (LessThanEq m) (GreaterThan n)) = ("lte", m, "gt", n)
rangeToKV (RangeLteGte (LessThanEq m) (GreaterThanEq n)) = ("lte", m, "gte", n)
data RangeExecution = RangeExecutionIndex
| RangeExecutionFielddata deriving (Eq, Show)
-- index for smaller ranges, fielddata for longer ranges
instance ToJSON RangeExecution where
toJSON RangeExecutionIndex = "index"
toJSON RangeExecutionFielddata = "fielddata"
data Term = Term { termField :: Text
, termValue :: Text } deriving (Eq, Show)

View File

@ -4,6 +4,10 @@
Elasticsearch client and query DSL for Haskell
** Examples
nope.jpg
** Possible future functionality
*** GeoShapeFilter
@ -22,6 +26,14 @@ http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-has-parent-filter.html
*** Indices Filter
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-indices-filter.html
*** Query Filter
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-query-filter.html
*** Runtime checking for cycles in data structures
check for n > 1 occurrences in DFS:

View File

@ -32,6 +32,7 @@ data Location = Location { lat :: Double
data Tweet = Tweet { user :: Text
, postDate :: UTCTime
, message :: Text
, age :: Int
, location :: Location }
deriving (Eq, Generic, Show)
@ -53,6 +54,7 @@ exampleTweet = Tweet { user = "bitemyapp"
(ModifiedJulianDay 55000)
(secondsToDiffTime 10)
, message = "Use haskell!"
, age = 10000
, location = Location 40.12 (-71.34) }
insertData :: IO ()
@ -185,3 +187,12 @@ main = hspec $ do
let search = Search Nothing (Just filter)
myTweet <- searchTweet search
myTweet `shouldBe` Right exampleTweet
it "returns document for range filter" $ do
_ <- insertData
let filter = RangeFilter "age"
(Right (RangeLtGt (LessThan 100000.0) (GreaterThan 1000.0)))
RangeExecutionIndex False
let search = Search Nothing (Just filter)
myTweet <- searchTweet search
myTweet `shouldBe` Right exampleTweet