@@ -204,6 +204,7 @@ module Database.V5.Bloodhound.Types
204 , CutoffFrequency(..)
204 , CutoffFrequency(..)
205 , Analyzer(..)
205 , Analyzer(..)
206 , Tokenizer(..)
206 , Tokenizer(..)
207 , MaxExpansions(..)
208 , MaxExpansions(..)
208 , Lenient(..)
209 , Lenient(..)
209 , MatchQueryType(..)
210 , MatchQueryType(..)
@@ -385,8 +386,11 @@ module Database.V5.Bloodhound.Types
385 , Analysis(..)
386 , Analysis(..)
386 , AnalyzerDefinition(..)
387 , AnalyzerDefinition(..)
387 , TokenizerDefinition(..)
388 , TokenizerDefinition(..)
389+ , TokenFilterDefinition(..)
388 , Ngram(..)
390 , Ngram(..)
389 , TokenChar(..)
391 , TokenChar(..)
392import Control.Applicative as A
396import Control.Applicative as A
@@ -602,32 +606,244 @@ data UpdatableIndexSetting = NumberOfReplicas ReplicaCount
602data Analysis = Analysis
606data Analysis = Analysis
603 { analysisAnalyzer :: M.Map Text AnalyzerDefinition
607 { analysisAnalyzer :: M.Map Text AnalyzerDefinition
604 , analysisTokenizer :: M.Map Text TokenizerDefinition
608 , analysisTokenizer :: M.Map Text TokenizerDefinition
609+ , analysisTokenFilter :: M.Map Text TokenFilterDefinition
605 } deriving (Eq,Show,Generic,Typeable)
610 } deriving (Eq,Show,Generic,Typeable)
607instance ToJSON Analysis where
612instance ToJSON Analysis where
608− toJSON (Analysis analyzer tokenizer) = object
613+ toJSON (Analysis analyzer tokenizer tokenFilter) = object
609 [ "analyzer" .= analyzer
614 [ "analyzer" .= analyzer
610 , "tokenizer" .= tokenizer
615 , "tokenizer" .= tokenizer
616+ , "filter" .= tokenFilter
613instance FromJSON Analysis where
619instance FromJSON Analysis where
614 parseJSON = withObject "Analysis" $ \m -> Analysis
620 parseJSON = withObject "Analysis" $ \m -> Analysis
615 <$> m .: "analyzer"
621 <$> m .: "analyzer"
616− <*> m .: "tokenizer"
622+ <*> m .:? "tokenizer" .!= M.empty
623+ <*> m .:? "filter" .!= M.empty
618data AnalyzerDefinition = AnalyzerDefinition
625data AnalyzerDefinition = AnalyzerDefinition
619 { analyzerDefinitionTokenizer :: Maybe Tokenizer
626 { analyzerDefinitionTokenizer :: Maybe Tokenizer
627+ , analyzerDefinitionFilter :: [TokenFilter]
620 } deriving (Eq,Show,Generic,Typeable)
628 } deriving (Eq,Show,Generic,Typeable)
622instance ToJSON AnalyzerDefinition where
630instance ToJSON AnalyzerDefinition where
623− toJSON (AnalyzerDefinition tokenizer) = object $ catMaybes
631+ toJSON (AnalyzerDefinition tokenizer tokenFilter) = object $ catMaybes
624 [ fmap ("tokenizer" .=) tokenizer
632 [ fmap ("tokenizer" .=) tokenizer
633+ , Just $ "filter" .= tokenFilter
627instance FromJSON AnalyzerDefinition where
636instance FromJSON AnalyzerDefinition where
628 parseJSON = withObject "AnalyzerDefinition" $ \m -> AnalyzerDefinition
637 parseJSON = withObject "AnalyzerDefinition" $ \m -> AnalyzerDefinition
629 <$> m .:? "tokenizer"
638 <$> m .:? "tokenizer"
639+ <*> m .:? "filter" .!= []
641+-- | Token filters are used to create custom analyzers.
642+data TokenFilterDefinition
643+ = TokenFilterDefinitionLowercase (Maybe Language)
644+ | TokenFilterDefinitionUppercase (Maybe Language)
645+ | TokenFilterDefinitionApostrophe
646+ | TokenFilterDefinitionReverse
647+ | TokenFilterDefinitionSnowball Language
648+ | TokenFilterDefinitionShingle Shingle
649+ deriving (Eq,Show,Generic)
651+instance ToJSON TokenFilterDefinition where
652+ toJSON x = case x of
653+ TokenFilterDefinitionLowercase mlang -> object $ catMaybes
654+ [ Just $ "type" .= ("lowercase" :: Text)
655+ , fmap (\lang -> "language" .= languageToText lang) mlang
657+ TokenFilterDefinitionUppercase mlang -> object $ catMaybes
658+ [ Just $ "type" .= ("uppercase" :: Text)
659+ , fmap (\lang -> "language" .= languageToText lang) mlang
661+ TokenFilterDefinitionApostrophe -> object
662+ [ "type" .= ("apostrophe" :: Text)
664+ TokenFilterDefinitionReverse -> object
665+ [ "type" .= ("reverse" :: Text)
667+ TokenFilterDefinitionSnowball lang -> object
668+ [ "type" .= ("snowball" :: Text)
669+ , "language" .= languageToText lang
671+ TokenFilterDefinitionShingle s -> object
672+ [ "type" .= ("shingle" :: Text)
673+ , "max_shingle_size" .= shingleMaxSize s
674+ , "min_shingle_size" .= shingleMinSize s
675+ , "output_unigrams" .= shingleOutputUnigrams s
676+ , "output_unigrams_if_no_shingles" .= shingleOutputUnigramsIfNoShingles s
677+ , "token_separator" .= shingleTokenSeparator s
678+ , "filler_token" .= shingleFillerToken s
681+instance FromJSON TokenFilterDefinition where
682+ parseJSON = withObject "TokenFilterDefinition" $ \m -> do
685+ "reverse" -> return TokenFilterDefinitionReverse
686+ "apostrophe" -> return TokenFilterDefinitionApostrophe
687+ "lowercase" -> TokenFilterDefinitionLowercase
688+ <$> m .:? "language"
689+ "uppercase" -> TokenFilterDefinitionUppercase
690+ <$> m .:? "language"
691+ "snowball" -> TokenFilterDefinitionSnowball
693+ "shingle" -> fmap TokenFilterDefinitionShingle $ Shingle
694+ <$> (fmap.fmap) unStringlyTypedInt (m .:? "max_shingle_size") .!= 2
695+ <*> (fmap.fmap) unStringlyTypedInt (m .:? "min_shingle_size") .!= 2
696+ <*> (fmap.fmap) unStringlyTypedBool (m .:? "output_unigrams") .!= True
697+ <*> (fmap.fmap) unStringlyTypedBool (m .:? "output_unigrams_if_no_shingles") .!= False
698+ <*> m .:? "token_separator" .!= " "
699+ <*> m .:? "filler_token" .!= "_"
700+ _ -> fail ("unrecognized token filter type: " ++ T.unpack t)
702+-- | The set of languages that can be passed to various analyzers,
703+-- filters, etc. in ElasticSearch. Most data types in this module
704+-- that have a 'Language' field are actually only actually to
705+-- handle a subset of these languages. Consult the official
706+-- ElasticSearch documentation to see what is actually supported.
746+ deriving (Show,Eq,Generic)
748+instance ToJSON Language where
749+ toJSON = Data.Aeson.String . languageToText
751+instance FromJSON Language where
752+ parseJSON = withText "Language" $ \t -> case languageFromText t of
753+ Nothing -> fail "not a supported ElasticSearch language"
754+ Just lang -> return lang
756+languageToText :: Language -> Text
757+languageToText x = case x of
759+ Armenian -> "armenian"
761+ Bengali -> "bengali"
762+ Brazilian -> "brazilian"
763+ Bulgarian -> "bulgarian"
764+ Catalan -> "catalan"
769+ English -> "english"
770+ Finnish -> "finnish"
772+ Galician -> "galician"
774+ German2 -> "german2"
777+ Hungarian -> "hungarian"
778+ Indonesian -> "indonesian"
780+ Italian -> "italian"
782+ Latvian -> "latvian"
783+ Lithuanian -> "lithuanian"
785+ Norwegian -> "norwegian"
786+ Persian -> "persian"
788+ Portuguese -> "portuguese"
789+ Romanian -> "romanian"
790+ Russian -> "russian"
792+ Spanish -> "spanish"
793+ Swedish -> "swedish"
795+ Turkish -> "turkish"
797+languageFromText :: Text -> Maybe Language
798+languageFromText x = case x of
799+ "arabic" -> Just Arabic
800+ "armenian" -> Just Armenian
801+ "basque" -> Just Basque
802+ "bengali" -> Just Bengali
803+ "brazilian" -> Just Brazilian
804+ "bulgarian" -> Just Bulgarian
805+ "catalan" -> Just Catalan
807+ "czech" -> Just Czech
808+ "danish" -> Just Danish
809+ "dutch" -> Just Dutch
810+ "english" -> Just English
811+ "finnish" -> Just Finnish
812+ "french" -> Just French
813+ "galician" -> Just Galician
814+ "german" -> Just German
815+ "german2" -> Just German2
816+ "greek" -> Just Greek
817+ "hindi" -> Just Hindi
818+ "hungarian" -> Just Hungarian
819+ "indonesian" -> Just Indonesian
820+ "irish" -> Just Irish
821+ "italian" -> Just Italian
823+ "latvian" -> Just Latvian
824+ "lithuanian" -> Just Lithuanian
825+ "lovins" -> Just Lovins
826+ "norwegian" -> Just Norwegian
827+ "persian" -> Just Persian
828+ "porter" -> Just Porter
829+ "portuguese" -> Just Portuguese
830+ "romanian" -> Just Romanian
831+ "russian" -> Just Russian
832+ "sorani" -> Just Sorani
833+ "spanish" -> Just Spanish
834+ "swedish" -> Just Swedish
836+ "turkish" -> Just Turkish
839+data Shingle = Shingle
840+ { shingleMaxSize :: Int
841+ , shingleMinSize :: Int
842+ , shingleOutputUnigrams :: Bool
843+ , shingleOutputUnigramsIfNoShingles :: Bool
844+ , shingleTokenSeparator :: Text
845+ , shingleFillerToken :: Text
846+ } deriving (Eq,Show,Generic,Typeable)
632data TokenizerDefinition
848data TokenizerDefinition
633 = TokenizerDefinitionNgram Ngram
849 = TokenizerDefinitionNgram Ngram
@@ -1135,6 +1351,8 @@ newtype Analyzer =
1135 Analyzer Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1351 Analyzer Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1136newtype Tokenizer =
1352newtype Tokenizer =
1137 Tokenizer Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1353 Tokenizer Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1354+newtype TokenFilter =
1355+ TokenFilter Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1138newtype MaxExpansions =
1356newtype MaxExpansions =
1139 MaxExpansions Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1357 MaxExpansions Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
@@ -4779,6 +4997,11 @@ newtype StringlyTypedInt = StringlyTypedInt { unStringlyTypedInt :: Int }
4779instance FromJSON StringlyTypedInt where
4997instance FromJSON StringlyTypedInt where
4780 parseJSON = fmap StringlyTypedInt . parseJSON . unStringlyTypeJSON
4998 parseJSON = fmap StringlyTypedInt . parseJSON . unStringlyTypeJSON
5000+newtype StringlyTypedBool = StringlyTypedBool { unStringlyTypedBool :: Bool }
5002+instance FromJSON StringlyTypedBool where
5003+ parseJSON = fmap StringlyTypedBool . parseJSON . unStringlyTypeJSON
4782instance FromJSON NodeFSTotalStats where
5005instance FromJSON NodeFSTotalStats where
4783 parseJSON = withObject "NodeFSTotalStats" parse
5006 parseJSON = withObject "NodeFSTotalStats" parse