git.iko.soy/typeable/bloodhound
on master help sign in
Merge pull request #94 from Soostone/optimize

Implement index optimization

commit27c29236d800a45459d8f8dbec3a1999c75544e3 authorChris Allen <cma@bitemyapp.com> dateWed 3 Feb 2016, 00:05 (11 years ago) parentbfb4adf1889edd
3 files changed+84−2
src/Database/Bloodhound/Client.hs+47−2 src/Database/Bloodhound/Types.hs+31 tests/tests.hs+6
src/Database/Bloodhound/Client.hs+47−2
@@ -1,5 +1,6 @@
11{-# LANGUAGE OverloadedStrings #-}
22{-# LANGUAGE RecordWildCards #-}
3+{-# LANGUAGE TupleSections #-}
34
45-------------------------------------------------------------------------------
56-- |
@@ -26,6 +27,7 @@ module Database.Bloodhound.Client
2627 , deleteIndex
2728 , updateIndexSettings
2829 , getIndexSettings
30+ , optimizeIndex
2931 , indexExists
3032 , openIndex
3133 , closeIndex
@@ -81,7 +83,7 @@ import qualified Data.HashMap.Strict as HM
8183import Data.Ix
8284import qualified Data.List as LS (filter, foldl')
8385import Data.List.NonEmpty (NonEmpty (..))
84−import Data.Maybe (fromMaybe, isJust)
86+import Data.Maybe (catMaybes, fromMaybe, isJust)
8587import Data.Monoid
8688import Data.Text (Text)
8789import qualified Data.Text as T
@@ -302,6 +304,48 @@ getIndexSettings (IndexName indexName) = do
302304 where url = joinPath [indexName, "_settings"]
303305
304306
307+-- | 'optimizeIndex' will optimize a single index, list of indexes or
308+-- all indexes. Note that this call will block until finishing but
309+-- will continue even if the request times out. Concurrent requests to
310+-- optimize an index while another is performing will block until the
311+-- previous one finishes. For more information see
312+-- <https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-optimize.html>. Nothing
313+-- worthwhile comes back in the reply body, so matching on the status
314+-- should suffice.
315+--
316+-- 'optimizeIndex' with a maxNumSegments of 1 and onlyExpungeDeletes
317+-- to True is the main way to release disk space back to the OS being
318+-- held by deleted documents.
319+--
320+-- Note that this API was deprecated in ElasticSearch 2.1 for the
321+-- almost completely identical forcemerge API. Adding support to that
322+-- API would be trivial but due to the significant breaking changes,
323+-- this library cannot currently be used with >= 2.0, so that feature was omitted.
324+--
325+-- >>> let ixn = IndexName "unoptimizedindex"
326+-- >>> _ <- runBH' $ deleteIndex ixn >> createIndex defaultIndexSettings ixn
327+-- >>> response <- runBH' $ optimizeIndex (IndexList (ixn :| [])) (defaultIndexOptimizationSettings { maxNumSegments = Just 1, onlyExpungeDeletes = True })
328+-- >>> respIsTwoHunna response
329+-- True
330+optimizeIndex :: MonadBH m => IndexSelection -> IndexOptimizationSettings -> m Reply
331+optimizeIndex ixs IndexOptimizationSettings {..} =
332+ bindM2 post url (return body)
333+ where url = addQuery params <$> joinPath [indexName, "_optimize"]
334+ params = catMaybes [ ("max_num_segments",) . Just . showText <$> maxNumSegments
335+ , Just ("only_expunge_deletes", Just (boolQP onlyExpungeDeletes))
336+ , Just ("flush", Just (boolQP flushAfterOptimize))
337+ ]
338+ indexName = indexSelectionName ixs
339+ boolQP True = "true"
340+ boolQP False = "false"
341+ body = Nothing
342+
343+
344+-------------------------------------------------------------------------------
345+indexSelectionName :: IndexSelection -> Text
346+indexSelectionName (IndexList names) = T.intercalate "," [n | IndexName n <- toList names]
347+indexSelectionName AllIndexes = "_all"
348+
305349deepMerge :: [Object] -> Object
306350deepMerge = LS.foldl' go mempty
307351 where go acc = LS.foldl' go' acc . HM.toList
@@ -395,6 +439,7 @@ closeIndex = openOrCloseIndexes CloseIndex
395439-- >>> let aliasName = IndexName "an-alias"
396440-- >>> let iAlias = IndexAlias src (IndexAliasName aliasName)
397441-- >>> let aliasCreate = IndexAliasCreate Nothing Nothing
442+-- >>> _ <- runBH' $ deleteIndex src
398443-- >>> respIsTwoHunna <$> runBH' (createIndex defaultIndexSettings src)
399444-- True
400445-- >>> runBH' $ indexExists src
@@ -484,7 +529,7 @@ versionCtlParams cfg =
484529 ExternalGTE (ExternalDocVersion v) -> versionParams v "external_gte"
485530 ForceVersion (ExternalDocVersion v) -> versionParams v "force"
486531 where
487− vt = T.pack . show . docVersionNumber
532+ vt = showText . docVersionNumber
488533 versionParams v t = [ ("version", Just $ vt v)
489534 , ("version_type", Just t)
490535 ]
src/Database/Bloodhound/Types.hs+31
@@ -141,6 +141,9 @@ module Database.Bloodhound.Types
141141 , FieldName(..)
142142 , Script(..)
143143 , IndexName(..)
144+ , IndexSelection(..)
145+ , IndexOptimizationSettings(..)
146+ , defaultIndexOptimizationSettings
144147 , TemplateName(..)
145148 , TemplatePattern(..)
146149 , MappingName(..)
@@ -384,6 +387,28 @@ data IndexSettings =
384387defaultIndexSettings :: IndexSettings
385388defaultIndexSettings = IndexSettings (ShardCount 3) (ReplicaCount 2)
386389
390+
391+{-| 'IndexOptimizationSettings' is used to configure index optimization. See
392+ <https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-optimize.html>
393+ for more info.
394+-}
395+data IndexOptimizationSettings =
396+ IndexOptimizationSettings { maxNumSegments :: Maybe Int
397+ -- ^ Number of segments to optimize to. 1 will fully optimize the index. If omitted, the default behavior is to only optimize if the server deems it necessary.
398+ , onlyExpungeDeletes :: Bool
399+ -- ^ Should the optimize process only expunge segments with deletes in them? If the purpose of the optimization is to free disk space, this should be set to True.
400+ , flushAfterOptimize :: Bool
401+ -- ^ Should a flush be performed after the optimize.
402+ } deriving (Eq, Show, Generic, Typeable)
403+
404+
405+{-| 'defaultIndexOptimizationSettings' implements the default settings that
406+ ElasticSearch uses for index optimization. 'maxNumSegments' is Nothing,
407+ 'onlyExpungeDeletes' is False, and flushAfterOptimize is True.
408+-}
409+defaultIndexOptimizationSettings :: IndexOptimizationSettings
410+defaultIndexOptimizationSettings = IndexOptimizationSettings Nothing False True
411+
387412{-| 'UpdatableIndexSetting' are settings which may be updated after an index is created.
388413
389414 <https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html>
@@ -770,6 +795,12 @@ newtype ReplicaCount = ReplicaCount Int deriving (Eq, Show, Generic, ToJSON, Typ
770795-}
771796newtype IndexName = IndexName Text deriving (Eq, Generic, Show, ToJSON, FromJSON, Typeable)
772797
798+{-| 'IndexSelection' is used for APIs which take a single index, a list of
799+ indexes, or the special @_all@ index.
800+-}
801+data IndexSelection = IndexList (NonEmpty IndexName)
802+ | AllIndexes deriving (Eq, Generic, Show, Typeable)
803+
773804{-| 'TemplateName' is used to describe which template to query/create/delete
774805-}
775806newtype TemplateName = TemplateName Text deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
tests/tests.hs+6
@@ -1446,6 +1446,12 @@ main = hspec $ do
14461446 (IndexSettings (ShardCount 1) (ReplicaCount 0))
14471447 (NE.toList updates))
14481448
1449+ describe "Index Optimization" $ do
1450+ it "returns a successful response upon completion" $ withTestEnv $ do
1451+ _ <- createExampleIndex
1452+ resp <- optimizeIndex (IndexList (testIndex :| [])) defaultIndexOptimizationSettings
1453+ liftIO $ validateStatus resp 200
1454+
14491455 describe "JSON instances" $ do
14501456 propJSON (Proxy :: Proxy Version)
14511457 propJSON (Proxy :: Proxy IndexName)