git.iko.soy/typeable/bloodhound
on master help sign in
examples!
commit652852cb4557e53df9303d0dc9df0c9e8636dda6 authorChris Allen <cma@bitemyapp.com> dateThu 11 Dec 2014, 20:34 (12 years ago) parent5c2ebe8
1 file changed+73−16
src/Database/Bloodhound/Client.hs+73−16
src/Database/Bloodhound/Client.hs+73−16
@@ -16,7 +16,8 @@
1616module Database.Bloodhound.Client
1717 ( -- * Bloodhound client functions
1818 -- | The examples in this module assume the following code has been run.
19− -- The :{ and :} will only work in GHCi.
19+ -- The :{ and :} will only work in GHCi. You'll only need the data types
20+ -- and typeclass instances for the functions that make use of them.
2021
2122 -- $setup
2223
@@ -64,6 +65,7 @@ import Database.Bloodhound.Types
6465
6566-- $setup
6667-- >>> :set -XOverloadedStrings
68+-- >>> :set -XDeriveGeneric
6769-- >>> import Database.Bloodhound
6870-- >>> import Test.DocTest.Prop (assert)
6971-- >>> let testServer = (Server "http://localhost:9200")
@@ -73,6 +75,9 @@ import Database.Bloodhound.Types
7375-- >>> data TweetMapping = TweetMapping deriving (Eq, Show)
7476-- >>> _ <- deleteIndex testServer testIndex
7577-- >>> _ <- deleteMapping testServer testIndex testMapping
78+-- >>> import GHC.Generics
79+-- >>> import Data.Time.Calendar (Day (..))
80+-- >>> import Data.Time.Clock (UTCTime (..), secondsToDiffTime)
7681-- >>> :{
7782--instance ToJSON TweetMapping where
7883-- toJSON TweetMapping =
@@ -80,9 +85,29 @@ import Database.Bloodhound.Types
8085-- object ["properties" .=
8186-- object ["location" .=
8287-- object ["type" .= ("geo_point" :: Text)]]]]
88+--data Location = Location { lat :: Double
89+-- , lon :: Double } deriving (Eq, Generic, Show)
90+--data Tweet = Tweet { user :: Text
91+-- , postDate :: UTCTime
92+-- , message :: Text
93+-- , age :: Int
94+-- , location :: Location } deriving (Eq, Generic, Show)
95+--exampleTweet = Tweet { user = "bitemyapp"
96+-- , postDate = UTCTime
97+-- (ModifiedJulianDay 55000)
98+-- (secondsToDiffTime 10)
99+-- , message = "Use haskell!"
100+-- , age = 10000
101+-- , location = Location 40.12 (-71.34) }
102+--instance ToJSON Tweet
103+--instance FromJSON Tweet
104+--instance ToJSON Location
105+--instance FromJSON Location
106+--data BulkTest = BulkTest { name :: Text } deriving (Eq, Generic, Show)
107+--instance FromJSON BulkTest
108+--instance ToJSON BulkTest
83109-- :}
84110
85−
86111mkShardCount :: Int -> Maybe ShardCount
87112mkShardCount n
88113 | n < 1 = Nothing
@@ -160,8 +185,11 @@ deleteIndex :: Server -> IndexName -> IO Reply
160185deleteIndex (Server server) (IndexName indexName) =
161186 delete $ joinPath [server, indexName]
162187
188+statusCodeIs :: Int -> Reply -> Bool
189+statusCodeIs n resp = NHTS.statusCode (responseStatus resp) == n
190+
163191respIsTwoHunna :: Reply -> Bool
164−respIsTwoHunna resp = NHTS.statusCode (responseStatus resp) == 200
192+respIsTwoHunna = statusCodeIs 200
165193
166194existentialQuery :: String -> IO (Reply, Bool)
167195existentialQuery url = do
@@ -177,10 +205,8 @@ indexExists (Server server) (IndexName indexName) = do
177205-- | 'refreshIndex' will force a refresh on an index. You must
178206-- do this if you want to read what you wrote.
179207--
180−-- >>> response <- createIndex testServer defaultIndexSettings testIndex
181−-- >>> response <- refreshIndex testServer testIndex
182−-- >>> respIsTwoHunna response
183−-- True
208+-- >>> _ <- createIndex testServer defaultIndexSettings testIndex
209+-- >>> _ <- refreshIndex testServer testIndex
184210refreshIndex :: Server -> IndexName -> IO Reply
185211refreshIndex (Server server) (IndexName indexName) =
186212 post url Nothing
@@ -206,10 +232,10 @@ closeIndex = openOrCloseIndexes CloseIndex
206232-- | 'putMapping' is an HTTP PUT and has upsert semantics. Mappings are schemas
207233-- for documents in indexes.
208234--
209−-- >>> response <- createIndex testServer defaultIndexSettings testIndex
235+-- >>> _ <- createIndex testServer defaultIndexSettings testIndex
210236-- >>> resp <- putMapping testServer testIndex testMapping TweetMapping
211−-- >>> respIsTwoHunna resp
212−-- True
237+-- >>> print resp
238+-- Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Content-Type","application/json; charset=UTF-8"),("Content-Length","21")], responseBody = "{\"acknowledged\":true}", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose}
213239putMapping :: ToJSON a => Server -> IndexName
214240 -> MappingName -> a -> IO Reply
215241putMapping (Server server) (IndexName indexName) (MappingName mappingName) mapping =
@@ -220,18 +246,24 @@ putMapping (Server server) (IndexName indexName) (MappingName mappingName) mappi
220246-- | 'deleteMapping' is an HTTP DELETE and deletes a mapping for a given index.
221247-- Mappings are schemas for documents in indexes.
222248--
223−-- >>> response <- createIndex testServer defaultIndexSettings testIndex
224−-- >>> resp <- putMapping testServer testIndex testMapping TweetMapping
225−-- >>> respIsTwoHunna resp
226−-- True
249+-- >>> _ <- createIndex testServer defaultIndexSettings testIndex
250+-- >>> _ <- putMapping testServer testIndex testMapping TweetMapping
227251-- >>> resp <- deleteMapping testServer testIndex testMapping
228−-- >>> respIsTwoHunna resp
229−-- True
252+-- >>> print resp
253+-- Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("Content-Type","application/json; charset=UTF-8"),("Content-Length","21")], responseBody = "{\"acknowledged\":true}", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose}
230254deleteMapping :: Server -> IndexName -> MappingName -> IO Reply
231255deleteMapping (Server server) (IndexName indexName)
232256 (MappingName mappingName) =
233257 delete $ joinPath [server, indexName, mappingName, "_mapping"]
234258
259+-- | 'indexDocument' is the primary way to save a single document in
260+-- Elasticsearch. The document itself is simply something we can
261+-- convert into a JSON 'Value'. The 'DocId' will function as the
262+-- primary key for the document.
263+--
264+-- >>> resp <- indexDocument testServer testIndex testMapping exampleTweet (DocId "1")
265+-- >>> print resp
266+-- Response {responseStatus = Status {statusCode = 201, statusMessage = "Created"}, responseVersion = HTTP/1.1, responseHeaders = [("Content-Type","application/json; charset=UTF-8"),("Content-Length","74")], responseBody = "{\"_index\":\"twitter\",\"_type\":\"tweet\",\"_id\":\"1\",\"_version\":1,\"created\":true}", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose}
235267indexDocument :: ToJSON doc => Server -> IndexName -> MappingName
236268 -> doc -> DocId -> IO Reply
237269indexDocument (Server server) (IndexName indexName)
@@ -240,17 +272,36 @@ indexDocument (Server server) (IndexName indexName)
240272 where url = joinPath [server, indexName, mappingName, docId]
241273 body = Just (encode document)
242274
275+-- | 'deleteDocument' is the primary way to delete a single document.
276+--
277+-- >>> _ <- deleteDocument testServer testIndex testMapping (DocId "1")
243278deleteDocument :: Server -> IndexName -> MappingName
244279 -> DocId -> IO Reply
245280deleteDocument (Server server) (IndexName indexName)
246281 (MappingName mappingName) (DocId docId) =
247282 delete $ joinPath [server, indexName, mappingName, docId]
248283
284+-- | 'bulk' uses Elasticsearch's bulk API at
285+-- http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-bulk.html
286+-- to perform bulk operations. The 'BulkOperation' data type encodes the
287+-- index/update/delete/create operations. You pass a 'V.Vector' of 'BulkOperation's
288+-- and a 'Server' to 'bulk' in order to send those operations up to your Elasticsearch
289+-- server to be performed. I changed from [BulkOperation] to a Vector due to memory overhead.
290+--
291+-- >>> let stream = V.fromList [BulkIndex testIndex testMapping (DocId "2") (toJSON (BulkTest "blah"))]
292+-- >>> _ <- bulk testServer stream
293+-- >>> _ <- refreshIndex testServer testIndex
249294bulk :: Server -> V.Vector BulkOperation -> IO Reply
250295bulk (Server server) bulkOps = post url body where
251296 url = joinPath [server, "_bulk"]
252297 body = Just $ encodeBulkOperations bulkOps
253298
299+-- | 'encodeBulkOperations' is a convenience function for dumping a vector of 'BulkOperation'
300+-- into an 'L.ByteString'
301+--
302+-- >>> let bulkOps = V.fromList [BulkIndex testIndex testMapping (DocId "2") (toJSON (BulkTest "blah"))]
303+-- >>> encodeBulkOperations bulkOps
304+-- "\n{\"index\":{\"_type\":\"tweet\",\"_id\":\"2\",\"_index\":\"twitter\"}}\n{\"name\":\"blah\"}\n"
254305encodeBulkOperations :: V.Vector BulkOperation -> L.ByteString
255306encodeBulkOperations stream = collapsed where
256307 blobs = fmap encodeBulkOperation stream
@@ -267,6 +318,12 @@ mkBulkStreamValue operation indexName mappingName docId =
267318 , "_type" .= mappingName
268319 , "_id" .= docId]]
269320
321+-- | 'encodeBulkOperation' is a convenience function for dumping a single 'BulkOperation'
322+-- into an 'L.ByteString'
323+--
324+-- >>> let bulkOp = BulkIndex testIndex testMapping (DocId "2") (toJSON (BulkTest "blah"))
325+-- >>> encodeBulkOperation bulkOp
326+-- "{\"index\":{\"_type\":\"tweet\",\"_id\":\"2\",\"_index\":\"twitter\"}}\n{\"name\":\"blah\"}"
270327encodeBulkOperation :: BulkOperation -> L.ByteString
271328encodeBulkOperation (BulkIndex (IndexName indexName)
272329 (MappingName mappingName)