git.iko.soy/typeable/bloodhound
on master help sign in
refactor of dispatch, began query expansion
commitc4becf956a2cbd3b98aba7d86ca7296352a1a8c0 authorChris Allen <cma@bitemyapp.com> dateSat 19 Apr 2014, 06:09 (12 years ago) parent46ad68e
3 files changed+182−62
Database/Bloodhound/Client.hs+44−46 Database/Bloodhound/Types.hs+137−15 README.org+1−1
Database/Bloodhound/Client.hs+44−46
@@ -25,11 +25,17 @@ import Data.Text (Text)
2525import Network.HTTP.Conduit
2626import qualified Network.HTTP.Types.Method as NHTM
2727import qualified Network.HTTP.Types.Status as NHTS
28+import Prelude hiding (head)
2829
2930import Database.Bloodhound.Types
3031import Database.Bloodhound.Types.Class
3132import Database.Bloodhound.Types.Instances
3233
34+-- find way to avoid destructuring Servers and Indexes?
35+-- make get, post, put, delete helpers.
36+-- make dispatch take URL last for better variance and
37+-- utilization of partial application
38+
3339mkShardCount :: Int -> Maybe ShardCount
3440mkShardCount n
3541 | n < 1 = Nothing
@@ -47,9 +53,9 @@ responseIsError resp = NHTS.statusCode (responseStatus resp) > 299
4753
4854emptyBody = L.pack ""
4955
50−dispatch :: String -> Method -> Maybe L.ByteString
56+dispatch :: Method -> String -> Maybe L.ByteString
5157 -> IO Reply
52−dispatch url method body = do
58+dispatch method url body = do
5359 initReq <- parseUrl url
5460 let reqBody = RequestBodyLBS $ fromMaybe emptyBody body
5561 let req = initReq { method = method
@@ -60,6 +66,16 @@ dispatch url method body = do
6066joinPath :: [String] -> String
6167joinPath = intercalate "/"
6268
69+delete = flip (dispatch NHTM.methodDelete) $ Nothing
70+get = flip (dispatch NHTM.methodGet) $ Nothing
71+head = flip (dispatch NHTM.methodHead) $ Nothing
72+put = dispatch NHTM.methodPost
73+post = dispatch NHTM.methodPost
74+
75+-- indexDocument s ix name doc = put (root </> s </> ix </> name </> doc) (Just encode doc)
76+-- http://hackage.haskell.org/package/http-client-lens-0.1.0/docs/Network-HTTP-Client-Lens.html
77+-- https://github.com/supki/libjenkins/blob/master/src/Jenkins/Rest/Internal.hs
78+
6379getStatus :: Server -> IO (Maybe (Status Version))
6480getStatus (Server server) = do
6581 request <- parseUrl $ joinPath [server]
@@ -68,36 +84,31 @@ getStatus (Server server) = do
6884
6985createIndex :: Server -> IndexSettings -> IndexName -> IO Reply
7086createIndex (Server server) indexSettings (IndexName indexName) =
71− dispatch url method body where
72− url = joinPath [server, indexName]
73− method = NHTM.methodPut
74− body = Just $ encode indexSettings
87+ put url body
88+ where url = joinPath [server, indexName]
89+ body = Just $ encode indexSettings
7590
7691deleteIndex :: Server -> IndexName -> IO Reply
7792deleteIndex (Server server) (IndexName indexName) =
78− dispatch url method body where
79− url = joinPath [server, indexName]
80− method = NHTM.methodDelete
81− body = Nothing
93+ delete $ joinPath [server, indexName]
8294
8395respIsTwoHunna :: Reply -> Bool
8496respIsTwoHunna resp = NHTS.statusCode (responseStatus resp) == 200
8597
8698existentialQuery url = do
87− reply <- dispatch url NHTM.methodHead Nothing
99+ reply <- head url
88100 return (reply, respIsTwoHunna reply)
89101
90102indexExists :: Server -> IndexName -> IO Bool
91103indexExists (Server server) (IndexName indexName) = do
92104 (reply, exists) <- existentialQuery url
93− return exists where
94− url = joinPath [server, indexName]
105+ return exists
106+ where url = joinPath [server, indexName]
95107
96108refreshIndex :: Server -> IndexName -> IO Reply
97−refreshIndex (Server server) (IndexName indexName) = dispatch url method body where
98− url = joinPath [server, indexName, "_refresh"]
99− method = NHTM.methodPost
100− body = Nothing
109+refreshIndex (Server server) (IndexName indexName) =
110+ post url Nothing
111+ where url = joinPath [server, indexName, "_refresh"]
101112
102113stringifyOCIndex oci = case oci of
103114 OpenIndex -> "_open"
@@ -105,11 +116,9 @@ stringifyOCIndex oci = case oci of
105116
106117openOrCloseIndexes :: OpenCloseIndex -> Server -> IndexName -> IO Reply
107118openOrCloseIndexes oci (Server server) (IndexName indexName) =
108− dispatch url method body where
109− ociString = stringifyOCIndex oci
110− url = joinPath [server, indexName, ociString]
111− method = NHTM.methodPost
112− body = Nothing
119+ post url Nothing
120+ where ociString = stringifyOCIndex oci
121+ url = joinPath [server, indexName, ociString]
113122
114123openIndex :: Server -> IndexName -> IO Reply
115124openIndex = openOrCloseIndexes OpenIndex
@@ -120,40 +129,31 @@ closeIndex = openOrCloseIndexes CloseIndex
120129createMapping :: ToJSON a => Server -> IndexName
121130 -> MappingName -> a -> IO Reply
122131createMapping (Server server) (IndexName indexName) (MappingName mappingName) mapping =
123− dispatch url method body where
124− url = joinPath [server, indexName, mappingName, "_mapping"]
125− method = NHTM.methodPut
126− body = Just $ encode mapping
132+ put url body
133+ where url = joinPath [server, indexName, mappingName, "_mapping"]
134+ body = Just $ encode mapping
127135
128136deleteMapping :: Server -> IndexName -> MappingName -> IO Reply
129137deleteMapping (Server server) (IndexName indexName) (MappingName mappingName) =
130− dispatch url method body where
131− url = joinPath [server, indexName, mappingName, "_mapping"]
132− method = NHTM.methodDelete
133− body = Nothing
138+ delete $ joinPath [server, indexName, mappingName, "_mapping"]
134139
135140indexDocument :: ToJSON doc => Server -> IndexName -> MappingName
136141 -> doc -> DocId -> IO Reply
137142indexDocument (Server server) (IndexName indexName)
138143 (MappingName mappingName) document (DocId docId) =
139− dispatch url method body where
140− url = joinPath [server, indexName, mappingName, docId]
141− method = NHTM.methodPut
142− body = Just (encode document)
144+ put url body
145+ where url = joinPath [server, indexName, mappingName, docId]
146+ body = Just (encode document)
143147
144148deleteDocument :: Server -> IndexName -> MappingName
145149 -> DocId -> IO Reply
146150deleteDocument (Server server) (IndexName indexName)
147151 (MappingName mappingName) (DocId docId) =
148− dispatch url method body where
149− url = joinPath [server, indexName, mappingName, docId]
150− method = NHTM.methodDelete
151− body = Nothing
152+ delete $ joinPath [server, indexName, mappingName, docId]
152153
153154bulk :: Server -> [BulkOperation] -> IO Reply
154−bulk (Server server) bulkOps = dispatch url method body where
155+bulk (Server server) bulkOps = post url body where
155156 url = joinPath [server, "_bulk"]
156− method = NHTM.methodPost
157157 body = Just $ collapseStream bulkOps
158158
159159collapseStream :: [BulkOperation] -> L.ByteString
@@ -201,20 +201,18 @@ getStreamChunk (BulkUpdate (IndexName indexName)
201201getDocument :: Server -> IndexName -> MappingName
202202 -> DocId -> IO Reply
203203getDocument (Server server) (IndexName indexName) (MappingName mappingName) (DocId docId) =
204− dispatch url method body where
205− url = joinPath [server, indexName, mappingName, docId]
206− method = NHTM.methodGet
207− body = Nothing
204+ get $ joinPath [server, indexName, mappingName, docId]
208205
209206documentExists :: Server -> IndexName -> MappingName
210207 -> DocId -> IO Bool
211−documentExists (Server server) (IndexName indexName) (MappingName mappingName) (DocId docId) = do
208+documentExists (Server server) (IndexName indexName)
209+ (MappingName mappingName) (DocId docId) = do
212210 (reply, exists) <- existentialQuery url
213211 return exists where
214212 url = joinPath [server, indexName, mappingName, docId]
215213
216214dispatchSearch :: String -> Search -> IO Reply
217−dispatchSearch url search = dispatch url NHTM.methodPost (Just (encode search))
215+dispatchSearch url search = post url (Just (encode search))
218216
219217searchAll :: Server -> Search -> IO Reply
220218searchAll (Server server) search = dispatchSearch url search where
Database/Bloodhound/Types.hs+137−15
@@ -174,20 +174,32 @@ type PrefixValue = Text
174174
175175data BooleanOperator = And | Or deriving (Eq, Show)
176176
177−newtype IndexName = IndexName String deriving (Eq, Generic, Show)
178−newtype MappingName = MappingName String deriving (Eq, Generic, Show)
179−newtype DocId = DocId String deriving (Eq, Generic, Show)
180−newtype QueryString = QueryString Text deriving (Eq, Show)
181−newtype FieldName = FieldName Text deriving (Eq, Show)
182−newtype CacheName = CacheName Text deriving (Eq, Show)
183−newtype CacheKey = CacheKey Text deriving (Eq, Show)
184−newtype Existence = Existence Bool deriving (Eq, Show)
185−newtype NullValue = NullValue Bool deriving (Eq, Show)
177+newtype IndexName = IndexName String deriving (Eq, Generic, Show)
178+newtype MappingName = MappingName String deriving (Eq, Generic, Show)
179+newtype DocId = DocId String deriving (Eq, Generic, Show)
180+newtype QueryString = QueryString Text deriving (Eq, Show)
181+newtype FieldName = FieldName Text deriving (Eq, Show)
182+newtype CacheName = CacheName Text deriving (Eq, Show)
183+newtype CacheKey = CacheKey Text deriving (Eq, Show)
184+newtype Existence = Existence Bool deriving (Eq, Show)
185+newtype NullValue = NullValue Bool deriving (Eq, Show)
186+newtype CutoffFrequency = CutoffFrequency Double deriving (Eq, Show)
187+newtype Analyzer = Analyzer Text deriving (Eq, Show)
188+newtype MaxExpansions = MaxExpansions Int deriving (Eq, Show)
189+newtype Lenient = Lenient Bool deriving (Eq, Show)
190+newtype Tiebreaker = Tiebreaker Double deriving (Eq, Show)
191+newtype Boost = Boost Double deriving (Eq, Show)
192+newtype MinimumMatch = MinimumMatch Int deriving (Eq, Show)
193+newtype MinimumMatchText = MinimumMatchText Text deriving (Eq, Show)
194+newtype DisableCoord = DisableCoord Bool deriving (Eq, Show)
195+newtype IgnoreTermFrequency = IgnoreTermFrequency Bool deriving (Eq, Show)
196+newtype MaxQueryTerms = MaxQueryTerms Int deriving (Eq, Show)
197+newtype Fuzziness = Fuzziness Double deriving (Eq, Show)
198+newtype PrefixLength = PrefixLength Int deriving (Eq, Show)
186199
187200unpackId :: DocId -> String
188201unpackId (DocId docId) = docId
189202
190−type Boost = Double
191203type TrackSortScores = Bool
192204type From = Int
193205type Size = Int
@@ -198,13 +210,121 @@ data Search = Search { queryBody :: Maybe Query
198210 -- default False
199211 , trackSortScores :: TrackSortScores
200212 , from :: From
201− , size :: Size} deriving (Eq, Show)
202−
203−data Query = TermQuery Term (Maybe Boost)
204− | ConstantScoreFilter Filter Boost
205− | ConstantScoreQuery Query Boost
213+ , size :: Size } deriving (Eq, Show)
214+
215+data Query = TermQuery Term (Maybe Boost)
216+ | QueryMatchQuery MatchQuery
217+ | QueryMultiMatchQuery MultiMatchQuery
218+ | QueryBoolQuery BoolQuery
219+ | QueryBoostingQuery BoostingQuery
220+ | QueryCommonTermsQuery CommonTermsQuery
221+ | ConstantScoreFilter Filter Boost
222+ | ConstantScoreQuery Query Boost
223+ | QueryDisMaxQuery DisMaxQuery
224+ | QueryFilteredQuery FilteredQuery
225+ | QueryFuzzyLikeThisQuery FuzzyLikeThisQuery
226+ | QueryFuzzyLikeFieldQuery FuzzyLikeFieldQuery
227+ | QueryFunctionScoreQuery FunctionScoreQuery
206228 deriving (Eq, Show)
207229
230+data FuzzyLikeFieldQuery =
231+ FuzzyLikeFieldQuery { fuzzyLikeField :: FieldName
232+ -- anaphora is good for the soul.
233+ , fuzzyLikeFieldText :: Text
234+ , fuzzyLikeFieldMaxQueryTerms :: MaxQueryTerms
235+ , fuzzyLikeFieldIgnoreTermFrequency :: IgnoreTermFrequency
236+ , fuzzyLikeFieldFuzziness :: Fuzziness
237+ , fuzzyLikeFieldPrefixLength :: PrefixLength
238+ , fuzzyLikeFieldBoost :: Boost
239+ , fuzzyLikeFieldAnalyzer :: Maybe Analyzer
240+ } deriving (Eq, Show)
241+
242+data FuzzyLikeThisQuery =
243+ FuzzyLikeThisQuery { fuzzyLikeFields :: [FieldName]
244+ , fuzzyLikeText :: Text
245+ , fuzzyLikeMaxQueryTerms :: MaxQueryTerms
246+ , fuzzyLikeIgnoreTermFrequency :: IgnoreTermFrequency
247+ , fuzzyLikeFuzziness :: Fuzziness
248+ , fuzzyLikePrefixLength :: PrefixLength
249+ , fuzzyLikeBoost :: Boost
250+ , fuzzyLikeAnalyzer :: Maybe Analyzer
251+ } deriving (Eq, Show)
252+
253+data FilteredQuery =
254+ FilteredQuery { filteredQuery :: Query
255+ , filteredFilter :: Filter } deriving (Eq, Show)
256+
257+data DisMaxQuery = DisMaxQuery { disMaxQueries :: [Query]
258+ -- default 0.0
259+ , disMaxTiebreaker :: Tiebreaker
260+ , disMaxBoost :: Maybe Boost
261+ } deriving (Eq, Show)
262+data MatchQuery =
263+ MatchQuery { matchQueryField :: FieldName
264+ , matchQueryQueryString :: QueryString
265+ , matchQueryOperator :: BooleanOperator
266+ , matchQueryZeroTerms :: ZeroTermsQuery
267+ , matchQueryCutoffFrequency :: Maybe CutoffFrequency
268+ , matchQueryMatchType :: Maybe MatchQueryType
269+ , matchQueryAnalyzer :: Maybe Analyzer
270+ , matchQueryMaxExpansions :: Maybe MaxExpansions
271+ , matchQueryLenient :: Maybe Lenient } deriving (Eq, Show)
272+
273+mkMatchQuery :: FieldName -> QueryString -> MatchQuery
274+mkMatchQuery field query = MatchQuery field query Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing
275+
276+data MatchQueryType = MatchPhrase
277+ | MatchPhrasePrefix deriving (Eq, Show)
278+
279+data MultiMatchQuery =
280+ MultiMatchQuery { multiMatchQueryFields :: [FieldName]
281+ , multiMatchQueryString :: QueryString
282+ , multiMatchQueryOperator :: BooleanOperator
283+ , multiMatchQueryZeroTerms :: ZeroTermsQuery
284+ , multiMatchQueryTiebreaker :: Maybe Tiebreaker
285+ , multiMatchQueryType :: Maybe MultiMatchQueryType
286+ , multiMatchQueryCutoffFrequency :: Maybe CutoffFrequency
287+ , multiMatchQueryAnalyzer :: Maybe Analyzer
288+ , multiMatchQueryMaxExpansions :: Maybe MaxExpansions
289+ , multiMatchQueryLenient :: Maybe Lenient } deriving (Eq, Show)
290+
291+data MultiMatchQueryType = MultiMatchBestFields
292+ | MultiMatchMostFields
293+ | MultiMatchCrossFields
294+ | MultiMatchPhrase
295+ | MultiMatchPhrasePrefix deriving (Eq, Show)
296+
297+data BoolQuery = BoolQuery { boolQueryMustMatch :: Maybe Query
298+ , boolQueryMustNotMatch :: Maybe Query
299+ , boolQueryShouldMatch :: Maybe [Query]
300+ , boolQueryMinimumShouldMatch :: Maybe MinimumMatch
301+ , boolQueryBoost :: Maybe Boost
302+ , boolQueryDisableCoord :: Maybe DisableCoord
303+ } deriving (Eq, Show)
304+
305+data BoostingQuery = BoostingQuery { positiveQuery :: Maybe Query
306+ , negativeQuery :: Maybe Query
307+ , positiveBoost :: Maybe Boost
308+ , negativeBoost :: Maybe Boost } deriving (Eq, Show)
309+
310+data CommonTermsQuery =
311+ CommonTermsQuery { commonQuery :: QueryString
312+ , commonCutoffFrequency :: CutoffFrequency
313+ , commonLowFreqOperator :: BooleanOperator
314+ , commonHighFreqOperator :: BooleanOperator
315+ , commonMinimumShouldMatch :: Maybe CommonMinimumMatch
316+ , commonBoost :: Maybe Boost
317+ , commonAnalyzer :: Maybe Analyzer
318+ , commonDisableCoord :: Maybe DisableCoord
319+ } deriving (Eq, Show)
320+
321+data CommonMinimumMatch = CommonMinimumMatchHighLow MinimumMatchHighLow
322+ | CommonMinimumMatch MinimumMatchText deriving (Eq, Show)
323+
324+data MinimumMatchHighLow =
325+ MinimumMatchHighLow { lowFreq :: MinimumMatch
326+ , highFreq :: MinimumMatch } deriving (Eq, Show)
327+
208328data Filter = AndFilter [Filter] Cache
209329 | OrFilter [Filter] Cache
210330 | NotFilter Filter Cache
@@ -223,6 +343,8 @@ data Filter = AndFilter [Filter] Cache
223343 | RegexpFilter FieldName Regexp RegexpFlags CacheName Cache CacheKey
224344 deriving (Eq, Show)
225345
346+data ZeroTermsQuery = ZeroTermsNone | ZeroTermsAll deriving (Eq, Show)
347+
226348-- lt, lte | gt, gte
227349newtype LessThan = LessThan Double deriving (Eq, Show)
228350newtype LessThanEq = LessThanEq Double deriving (Eq, Show)
README.org+1−1
@@ -11,7 +11,7 @@ Search doesn't have to be hard. Let the dog do it.
1111
1212** Stability
1313
14−Bloodhound is alpha at the moment. The library works fine, but I don't want to mislead anyone into thinking the API is final or stable. I wouldn't call the library "complete" or representative of everything you can do in Elasticsearch but being compared to clients in other languages the story here so far is good.
14+Bloodhound is alpha at the moment. The library works fine, but I don't want to mislead anyone into thinking the API is final or stable. I wouldn't call the library "complete" or representative of everything you can do in Elasticsearch but compared to clients in other languages, the usability is good.
1515
1616* Examples
1717