sphinx 0.2.1 → 0.3.3
raw patch · 7 files changed
+428/−153 lines, 7 filesdep +data-binary-ieee754dep ~basenew-uploader
Dependencies added: data-binary-ieee754
Dependency ranges changed: base
Files
- Text/Search/Sphinx.hs +204/−69
- Text/Search/Sphinx/Configuration.hs +7/−0
- Text/Search/Sphinx/ExcerptConfiguration.hs +61/−0
- Text/Search/Sphinx/Get.hs +40/−25
- Text/Search/Sphinx/Put.hs +12/−7
- Text/Search/Sphinx/Types.hs +92/−47
- sphinx.cabal +12/−5
Text/Search/Sphinx.hs view
@@ -1,55 +1,205 @@--- | This is the Haskell version of the Sphinx searchd client.+-- The following functions are not yet implemented:+-- setFilterFloatRange, setGeoAnchor+-- resetFilters, resetGroupBy+-- updateAttributes,+-- buildKeyWords, escapeString, status, open, close+module Text.Search.Sphinx ( module Text.Search.Sphinx+ , Configuration(..), defaultConfig+ ) where -module Text.Search.Sphinx ( Configuration (..)- , query- , defaultConfig- ) where+import qualified Text.Search.Sphinx.Types as T (+ VerCommand(VcSearch, VcExcerpt),+ SearchdCommand(ScSearch, ScExcerpt),+ Filter, Filter(..),+ fromEnumFilter, Filter(..),+ QueryStatus(..), toStatus, Status(..),+ SearchResult, Result(..), QueryResult(..)) -import Network-import IO hiding (bracket)-import System-import Control.Exception-import Data.Binary.Get-import Data.Binary.Put (runPut, Put)-import Data.ByteString.Lazy hiding (pack, length, map, groupBy, head)-import Data.ByteString.Lazy.Char8 (pack)-import qualified Data.ByteString.Lazy as BS-import Data.Char (ord, chr)+import Text.Search.Sphinx.Configuration (Configuration(..), defaultConfig)+import qualified Text.Search.Sphinx.ExcerptConfiguration as ExConf (ExcerptConfiguration(..))+import Text.Search.Sphinx.Get (times, getResult, readHeader, getStr)+import Text.Search.Sphinx.Put (num, num64, enum, list, numC, strC,+ numC64, stringIntList, str, cmd, verCmd)++import Data.Binary.Put (Put, runPut)+import Data.Binary.Get (runGet, getWord32be)+import qualified Data.ByteString.Lazy as BS (ByteString, length, hGet, hPut, tail, append) import Data.Int (Int64)-import Prelude hiding (readList)-import Text.Search.Sphinx.Get-import Text.Search.Sphinx.Put-import Text.Search.Sphinx.Configuration-import Text.Search.Sphinx.Types (SearchResult)-import qualified Text.Search.Sphinx.Types as T +import Network (connectTo, PortID(PortNumber))+import IO (Handle, hFlush)+import Data.Bits ((.|.)) -type Connection = (Handle, Configuration)+import Prelude hiding (filter, tail) +{- the funnest way to debug this is to run the same query with an existing working client and look at the difference+ - sudo tcpflow -i lo dst port 9306 +-}+import Debug.Trace; debug a = trace (show a) a -connect :: Configuration -> IO Connection-connect cfg = do connection <- connectTo (host cfg) (PortNumber $ fromIntegral $ port cfg)- bs <- hGet connection 4- let version = runGet getWord32be bs- myVersion = runPut (num 1)- hPut connection myVersion- return (connection, cfg)+{- weren't working properly, should try out on latest version now+setFilter :: Configuration -> String -> [Int64] -> Bool -> Configuration+setFilter cfg attr values exclude =+ let f = (T.FilterValues attr values)+ in addFilter cfg (if exclude then T.ExclusionFilter f else f) +setFilterRange :: Configuration -> String -> Int64 -> Int64 -> Bool -> Configuration+setFilterRange cfg attr min max exclude =+ let f = (T.FilterRange attr min max)+ in addFilter cfg (if exclude then T.ExclusionFilter f else f) +--setFilterFloatRange :: Configuration -> String -> Float -> Float -> Bool -> Configuration+--setFilterFloatRange cfg attr min max exclude =+ --let f = (T.FilterFloatRange attr min max)+ --in addFilter cfg (if exclude then T.ExclusionFilter f else f)++-- | alternative interface to setFilter* using Filter constructors+addFilter :: Configuration -> T.Filter -> Configuration+addFilter cfg filter = cfg { filters = filter : (filters cfg) }+ -}++-- | The 'query' function runs a single query against the Sphinx daemon.+query :: Configuration -- ^ The configuration+ -> String -- ^ The indexes, "*" means every index+ -> String -- ^ The query string+ -> IO (T.Result T.SearchResult) -- ^ just one search result back+query config indexes s = do+ conn <- connect (host config) (port config)+ let q = addQuery config s indexes ""+ results <- runQueries conn [q] 1+ return $ case results of+ T.Ok rs -> case head rs of -- there is just 1 result+ T.QueryOk result -> T.Ok result+ T.QueryWarning w result -> T.Warning w result+ T.QueryError code e -> T.Error code e+ T.Error code error -> T.Error code error+ T.Retry retry -> T.Retry retry+ T.Warning warning (result:results) -> case result of+ T.QueryOk result -> T.Warning warning result+ T.QueryWarning w result -> T.Warning (BS.append warning w) result+ T.QueryError code e -> T.Error code e+ +connect :: String -> Int -> IO Handle+connect host port = do+ connection <- connectTo host (PortNumber $ fromIntegral $ port)+ bs <- BS.hGet connection 4+ let version = runGet getWord32be bs+ myVersion = runPut (num 1)+ BS.hPut connection myVersion+ return connection++-- | TODO: add configuration options+buildExcerpts :: ExConf.ExcerptConfiguration -- ^ Contains host and port for connection and optional configuration for buildExcerpts+ -> [String] -- ^ list of document contents to be highlighted+ -> String -- ^ The indexes, "*" means every index+ -> String -- ^ The query string to use for excerpts+ -> IO (T.Result [BS.ByteString]) -- ^ the documents with excerpts highlighted+buildExcerpts config docs indexes words = do+ conn <- connect (ExConf.host config) (ExConf.port config)+ let req = runPut $ makeBuildExcerpt addExcerpt+ BS.hPut conn req+ hFlush conn+ (status, response) <- getResponse conn+ case status of+ T.OK -> return $ T.Ok (getResults response)+ T.WARNING -> return $ T.Warning (runGet getStr response) (getResults response)+ T.RETRY -> return $ T.Retry (errorMessage response)+ T.ERROR n -> return $ T.Error n (errorMessage response)+ where+ getResults response = runGet ((length docs) `times` getStr) response+ errorMessage response = BS.tail (BS.tail (BS.tail (BS.tail response)))++ makeBuildExcerpt putExcerpt = do+ cmd T.ScExcerpt+ verCmd T.VcExcerpt + num $ fromEnum $ BS.length (runPut putExcerpt)+ putExcerpt++ addExcerpt :: Put+ addExcerpt = do+ num 0 -- mode+ num $ excerptFlags config+ str indexes+ str words+ strC config [ExConf.beforeMatch, ExConf.afterMatch, ExConf.chunkSeparator]+ numC config [ExConf.limit, ExConf.around, ExConf.limitPassages, ExConf.limitWords, ExConf.startPassageId]+ str $ ExConf.htmlStripMode config+ list str docs++ modeFlag :: ExConf.ExcerptConfiguration -> (ExConf.ExcerptConfiguration -> Bool) -> Int -> Int+ modeFlag cfg setting value = if setting cfg then value else 0++ excerptFlags :: ExConf.ExcerptConfiguration -> Int+ excerptFlags cfg = foldl (.|.) 1 (map (\(s,v) -> modeFlag cfg s v) [+ (ExConf.exactPhrase, 2 )+ , (ExConf.singlePassage, 4 )+ , (ExConf.useBoundaries, 8 )+ , (ExConf.weightOrder, 16 )+ , (ExConf.queryMode, 32 )+ , (ExConf.forceAllWords, 64 )+ , (ExConf.loadFiles, 128 )+ , (ExConf.allowEmpty, 256 )+ ])+++-- | right now this is just a lower leve method used by the query method+-- | eventually it will be its own entry point that can run multiple queries by using addQuery+-- | right now it just runs the first query and ignores the rest+runQueries :: Handle -> [Put] -> Int -> IO (T.Result [T.QueryResult])+runQueries conn qs numQueries = do+ let nQueries = 1+ let req = runPut $ makeRunQuery (head qs) nQueries+ BS.hPut conn req+ hFlush conn+ getSearchResult conn nQueries+ where + makeRunQuery query n = do+ cmd T.ScSearch+ verCmd T.VcSearch+ num $ fromEnum $ BS.length (runPut query) + 4+ num n+ query++getSearchResult :: Handle -> Int -> IO (T.Result [T.QueryResult])+getSearchResult conn numResults = do+ (status, response) <- getResponse conn+ case status of+ T.OK -> return $ T.Ok (getResults response)+ T.WARNING -> return $ T.Warning (runGet getStr response) (getResults response)+ T.RETRY -> return $ T.Retry (errorMessage response)+ T.ERROR n -> return $ T.Error n (errorMessage response)+ where+ getResults response = runGet (numResults `times` getResult) response+ errorMessage response = BS.tail (BS.tail (BS.tail (BS.tail response)))++getResponse :: Handle -> IO (T.Status, BS.ByteString)+getResponse conn = do+ header <- BS.hGet conn 8+ let (status, version, len) = readHeader header+ if len == 0+ then error "received zero-sized searchd response (bad query?)"+ else return ()+ response <- BS.hGet conn (fromIntegral len)+ return (status, response)++-- | right now this is just a lower level method used by the query method+-- | when runQueries works properly this is used to run batched queries addQuery :: Configuration -> String -> String -> String -> Put-addQuery cfg query index comment = do- nums cfg [ offset+addQuery cfg query indexes comment = do+ numC cfg [ offset , limit- , T.matchMode . mode- , T.rank . ranker- , T.sort . sort]+ , fromEnum . mode+ , fromEnum . ranker+ , fromEnum . sort] str (sortBy cfg) str query- numList (weights cfg)- str index- num 1- num64s cfg [minId, maxId]- num 0 -- todo: pack len filters + filters+ list num (weights cfg)+ str indexes+ num 1 -- id64 range marker+ numC64 cfg [minId, maxId] -- id64 range++ list putFilter (filters cfg)+ enum (groupByFunc cfg) str (groupBy cfg) num (maxMatches cfg)@@ -58,39 +208,24 @@ num (retryCount cfg) num (retryDelay cfg) str (groupDistinct cfg)- num 0 -- anchor point: todo+ num 0 -- anchor point for setGeoAnchor stringIntList (indexWeights cfg) num (maxQueryTime cfg) stringIntList (fieldWeights cfg) str comment---- | The 'query' function queries the Sphinx daemon.-query :: Configuration -- ^ The configuration- -> String -- ^ The indexes, "*" means every index- -> String -- ^ The query string- -> IO SearchResult-query config indexes s = do- conn <- connect config- let q = addQuery config s indexes ""- results <- runQueries (fst conn) q 1- return $ head results -- We only do one query, so we always have one SearchResult--runQueries :: Handle -> Put -> Int -> IO [SearchResult]-runQueries conn q numQueries = do- let req = runPut (makeRunQuery q numQueries)- hPut conn req- hFlush conn- getResponse conn numQueries+ num 0 -- attribute overrides (none)+ str (selectClause cfg) -- select-list+ where+ {- Not working properly -}+ putFilter :: T.Filter -> Put+ putFilter (T.ExclusionFilter filter) = putFilter_ filter True+ putFilter filter = putFilter_ filter False -makeRunQuery query numQueries = do- cmd T.ScSearch- verCmd T.VcSearch- num $ fromEnum $ BS.length (runPut query) + 4- num numQueries- query+ putFilter_ f@(T.FilterValues attr values) ex = putFilter__ f attr (list num64) [values] ex+ putFilter_ f@(T.FilterRange attr min max) ex = putFilter__ f attr num64 [min, max] ex -getResponse conn numResults = do- header <- hGet conn 8- let x@(status, version, len) = readHeader header- response <- hGet conn (fromIntegral len)- return $ runGet (numResults `times` getResult) response+ putFilter__ filter attr puter values exclude = do+ str (debug attr)+ num $ (debug $ T.fromEnumFilter filter)+ mapM_ puter (debug values)+ num $ (debug $ fromEnum exclude)
Text/Search/Sphinx/Configuration.hs view
@@ -26,6 +26,8 @@ , minId :: Int -- | Maximum ID to match, 0 means no limit , maxId :: Int+ -- | attribute filters+ , filters :: [T.Filter] -- | Group-by sorting clause (to sort groups in result set with) , groupBy :: String -- | Group-by count-distinct attribute@@ -48,7 +50,10 @@ , maxQueryTime :: Int -- | Per-field-name weights , fieldWeights :: [(String, Int)]+ -- | attributes to select, defaults to '*'+ , selectClause :: String -- setSelect in regular API }+ deriving (Show) -- | A basic, default configuration. defaultConfig = Configuration {@@ -63,6 +68,7 @@ , sortBy = "" , minId = 0 , maxId = 0+ , filters = [] , groupSort = "@group desc" , groupBy = "" , groupByFunc = T.Day@@ -74,4 +80,5 @@ , indexWeights = [] , maxQueryTime = 0 , fieldWeights = []+ , selectClause = "*" }
+ Text/Search/Sphinx/ExcerptConfiguration.hs view
@@ -0,0 +1,61 @@+module Text.Search.Sphinx.ExcerptConfiguration where++-- import qualified Text.Search.Sphinx.Types as T++data ExcerptConfiguration = ExcerptConfiguration {+ -- | The hostname of the Sphinx daemon+ host :: String+ -- | The portnumber of the Sphinx daemon+ , port :: Int+ , beforeMatch :: String+ , afterMatch :: String+ , chunkSeparator :: String+ , limit :: Int+ , around :: Int+ , exactPhrase :: Bool+ , singlePassage :: Bool+ , useBoundaries :: Bool+ , weightOrder :: Bool+ -- | warning! broken on 1.10-beta (keep to default of false)+ , queryMode :: Bool+ , forceAllWords :: Bool+ , limitPassages :: Int+ , limitWords :: Int+ , startPassageId :: Int+ , loadFiles :: Bool+ , htmlStripMode :: String+ , allowEmpty :: Bool+}+ deriving (Show)++-- this is true to the API+defaultConfig = ExcerptConfiguration {+ port = 3312+ , host = "127.0.0.1"+ , beforeMatch = "<b>"+ , afterMatch = "</b>"+ , chunkSeparator = "..."+ , limit = 256+ , around = 5+ , exactPhrase = False+ , singlePassage = False+ , weightOrder = False+ , queryMode = False+ , forceAllWords = False+ , limitPassages = 0+ , limitWords = 0+ , useBoundaries = False+ , startPassageId = 1+ , loadFiles = False+ , htmlStripMode = "index" -- ^ "none", "strip", "index", and "retain". + , allowEmpty = False+}++-- this seems better to me+altConfig = defaultConfig {+ beforeMatch = "<span class='match'>"+ , afterMatch = "</span>"+ , chunkSeparator = " … "+ -- , queryMode = True Buggy!+ , forceAllWords = True+}
Text/Search/Sphinx/Get.hs view
@@ -1,62 +1,77 @@ module Text.Search.Sphinx.Get where import Data.Binary.Get+import Data.Binary.IEEE754+ import Data.Int (Int64) import Prelude hiding (readList) import Data.ByteString.Lazy hiding (pack, length, map, groupBy) import Control.Monad-import Text.Search.Sphinx.Types+import qualified Text.Search.Sphinx.Types as T+import Data.Maybe (isJust, fromJust) -- Utility functions getNum :: Get Int getNum = getWord32be >>= return . fromEnum +getFloat :: Get Float+getFloat = getFloat32be+ getNum64 :: Get Int64 getNum64 = getWord64be >>= return . fromIntegral -getNums = readList getNum readList f = do num <- getNum num `times` f times = replicateM-readField = readStr-readStr = do len <- getNum- getLazyByteString (fromIntegral len) +getStr = do len <- getNum+ getLazyByteString (fromIntegral len) -getResult :: Get SearchResult+getResult :: Get (T.QueryResult) getResult = do- status <- getNum- -- todo: we suppose the status is OK- fields <- readList readField- attrs <- readList readAttr- matchCount <- getNum- id64 <- getNum- matches <- matchCount `times` readMatch (id64 > 0) (map snd attrs)- [total, totalFound, time, numWords] <- 4 `times` getNum- wrds <- numWords `times` readWord- return (SearchResult matches total totalFound wrds)+ statusNum <- getNum+ case T.toQueryStatus statusNum of+ T.QueryERROR n -> do e <- getStr+ return $ T.QueryError statusNum e+ T.QueryOK -> getResultOk >>= return . T.QueryOk+ T.QueryWARNING -> do w <- getStr+ getResultOk >>= return . (T.QueryWarning w)+ where+ getResultOk = do+ fields <- readList getStr+ attrs <- readList readAttrPair+ matchCount <- getNum+ id64 <- getNum+ matches <- matchCount `times` readMatch (id64 > 0) (map snd attrs)+ [total, totalFound, time, numWords] <- 4 `times` getNum+ wrds <- numWords `times` readWord+ return $ T.SearchResult matches total totalFound wrds (map fst attrs) -readWord = do s <- readStr+readWord = do s <- getStr [doc, hits] <- 2 `times` getNum return (s, doc, hits) readMatch isId64 attrs = do doc <- if isId64 then getNum64 else (getNum >>= return . fromIntegral) weight <- getNum- matchAttrs <- mapM readMatchAttr attrs- return $ Match doc weight matchAttrs+ matchAttrs <- mapM readAttr attrs+ return $ T.Match doc weight matchAttrs+ where+ readAttr (T.AttrTMulti attr) = (readList (readAttr attr)) >>= return . T.AttrMulti+ readAttr T.AttrTBigInt = getNum64 >>= return . T.AttrBigInt+ readAttr T.AttrTString = getStr >>= return . T.AttrString+ readAttr T.AttrTUInt = getNum >>= return . T.AttrUInt+ readAttr T.AttrTFloat = getFloat >>= return . T.AttrFloat+ readAttr _ = getNum >>= return . T.AttrUInt -readMatchAttr AttrTFloat = error "readMatchAttr for AttrFloat not implemented yet."-readMatchAttr AttrTMulti = getNums >>= return . AttrMulti-readMatchAttr _ = getNum >>= return . AttrNum -readAttr = do- s <- readStr+readAttrPair = do+ s <- getStr t <- getNum return (s, toEnum t) readHeader = runGet $ do status <- getWord16be version <- getWord16be length <- getWord32be- return (status, version, length)+ return (T.toStatus $ fromIntegral status, version, length)
Text/Search/Sphinx/Put.hs view
@@ -1,22 +1,27 @@ module Text.Search.Sphinx.Put where +import Data.Int (Int64)+import Data.Binary (Word64) import Data.Binary.Put import Data.ByteString.Lazy hiding (pack, length, map, groupBy) import Data.ByteString.Lazy.Char8 (pack) import qualified Data.ByteString.Lazy as BS import qualified Text.Search.Sphinx.Types as T -num = putWord32be . toEnum-num64 = putWord64be . toEnum+num = putWord32be . fromIntegral+num64 i = putWord64be $ fromIntegral i+ enum :: Enum a => a -> Put enum = num . fromEnum-numList ls = do num (length ls)- mapM_ num ls-nums cfg = mapM_ (\x -> num $ x cfg)-num64s cfg = mapM_ (\x -> num64 $ x cfg) +list f ls = num (length ls) >> mapM_ f ls++numC cfg = mapM_ (\x -> num $ x cfg)+numC64 cfg = mapM_ (\x -> num64 $ x cfg)+strC cfg = mapM_ (\x -> str $ x cfg)+ stringIntList :: [(String, Int)] -> Put-stringIntList xs = num (length xs) >> mapM_ strInt xs+stringIntList xs = list strInt xs where strInt (s,i) = str s >> num i str :: String -> Put
Text/Search/Sphinx/Types.hs view
@@ -1,7 +1,10 @@-module Text.Search.Sphinx.Types where+module Text.Search.Sphinx.Types (+ module Text.Search.Sphinx.Types+ , ByteString ) where import Data.ByteString.Lazy (ByteString) import Data.Int (Int64)+import Data.Maybe (Maybe, isJust) -- | Search commands data SearchdCommand = ScSearch@@ -20,21 +23,35 @@ | VcKeywords deriving (Show) -verCommand VcSearch = 0x113-verCommand VcExcerpt = 0x100+-- | Important! only 1.1 compatible+verCommand VcSearch = 0x117+verCommand VcExcerpt = 0x102 verCommand VcUpdate = 0x101 verCommand VcKeywords = 0x100 -- | Searchd status codes-data Searchd = Ok- | Error- | Retry- | Warning- deriving (Show, Enum)+data Status = OK+ | RETRY+ | WARNING+ | ERROR Int+ deriving (Show) -searchd :: Searchd -> Int-searchd = fromEnum+-- | status from an individual query+data QueryStatus = QueryOK+ | QueryWARNING+ | QueryERROR Int+ deriving (Show) +toQueryStatus 0 = QueryOK+toQueryStatus 3 = QueryWARNING+toQueryStatus 2 = error "Didn't think retry was possible"+toQueryStatus n = QueryERROR n++toStatus 0 = OK+toStatus 2 = RETRY+toStatus 3 = WARNING+toStatus n = ERROR n+ -- | Match modes data MatchMode = All | Any@@ -45,19 +62,18 @@ | Extended2 -- extended engine V2 (TEMPORARY, WILL BE REMOVED) deriving (Show, Enum) -matchMode :: MatchMode -> Int-matchMode = fromEnum- -- | Ranking modes (ext2 only) data Rank = ProximityBm25 -- default mode, phrase proximity major factor and BM25 minor one | Bm25 -- statistical mode, BM25 ranking only (faster but worse quality) | None -- no ranking, all matches get a weight of 1 | WordCount -- simple word-count weighting, rank is a weighted sum of per-field keyword occurence counts+ | Proximity -- internally used to emulate SPH_MATCH_ALL queries+ | MatchAny -- internaly used to emulate SPHINX_MATCH_ANY searching mode+ | Fieldmask -- ?+ | Sph04 -- like ProximityBm25, but more weight given to matches at beginning or end of field+ | Total deriving (Show, Enum) -rank :: Rank -> Int-rank = fromEnum- -- | Sort modes data Sort = Relevance | AttrDesc@@ -67,45 +83,58 @@ | Expr deriving (Show, Enum) -sort :: Sort -> Int-sort = fromEnum- -- | Filter types-data Filter = Values- | Range- | FloatRange- deriving (Show, Enum)+data Filter = ExclusionFilter Filter+ | FilterValues String [Int64]+ | FilterRange String Int64 Int64+ -- TODO | FilterFloatRange attr Float Float+ deriving (Show) -filter :: Filter -> Int-filter = fromEnum+-- | shortcut for creating an exclusion filter+exclude filter = ExclusionFilter filter +fromEnumFilter (FilterValues _ _) = 0+fromEnumFilter (FilterRange _ _ _) = 1+-- fromEnumFilter (FilterFloatRange _ _ _) = 2+ -- | Attribute types-data AttrT = AttrTInteger- | AttrTTimestamp- | AttrTOrdinal- | AttrTBool- | AttrTFloat- | AttrTMulti+data AttrT = AttrTUInt -- unsigned 32-bit integer+ | AttrTTimestamp -- timestamp+ | AttrTStr2Ordinal -- ordinal string number (integer at search time, specially handled at indexing time)+ | AttrTBool -- boolean bit field+ | AttrTFloat -- floating point number (IEEE 32-bit)+ | AttrTBigInt -- signed 64-bit integer+ | AttrTString -- string (binary; in-memory)+ | AttrTWordCount -- string word count (integer at search time,tokenized and counted at indexing time)+ | AttrTMulti AttrT -- multiple values (0 or more) deriving (Show) instance Enum AttrT where toEnum = toAttrT fromEnum = attrT -toAttrT 1 = AttrTInteger+toAttrT 1 = AttrTUInt toAttrT 2 = AttrTTimestamp-toAttrT 3 = AttrTOrdinal+toAttrT 3 = AttrTStr2Ordinal toAttrT 4 = AttrTBool toAttrT 5 = AttrTFloat-toAttrT 0x40000000 = AttrTMulti +toAttrT 6 = AttrTBigInt+toAttrT 7 = AttrTString+toAttrT 8 = AttrTWordCount+toAttrT 0x40000001 = AttrTMulti AttrTUInt -attrT AttrTInteger = 1-attrT AttrTTimestamp = 2-attrT AttrTOrdinal = 3-attrT AttrTBool = 4-attrT AttrTFloat = 5-attrT AttrTMulti = 0x40000000+attrMultiMask = 0x40000000 +attrT AttrTUInt = 1+attrT AttrTTimestamp = 2+attrT AttrTStr2Ordinal = 3+attrT AttrTBool = 4+attrT AttrTFloat = 5+attrT AttrTBigInt = 6+attrT AttrTString = 7+attrT AttrTWordCount = 8+attrT (AttrTMulti AttrTUInt) = 0x40000001+ -- | Grouping functions data GroupByFunction = Day | Week@@ -115,9 +144,6 @@ | AttrPair deriving (Show, Enum) -groupByFunction :: GroupByFunction -> Int-groupByFunction = fromEnum- -- | The result of a query data SearchResult = SearchResult { -- | The matches@@ -126,11 +152,27 @@ , total :: Int -- | Total amount of matching documents in index. , totalFound :: Int- -- | List of processed words with the number of docs and the number of hits.+ -- | processed words with the number of docs and the number of hits. , words :: [(ByteString, Int, Int)]+ -- | List of attribute names returned in the result.+ -- | The Match will contain just the attribute values in the same order.+ , attributeNames :: [ByteString] } deriving Show +-- | a single query result, runQueries returns a list of these+data QueryResult = QueryOk SearchResult+ | QueryWarning ByteString SearchResult+ | QueryError Int ByteString+ deriving (Show)++-- | a result returned from searchd+data Result a = Ok a+ | Warning ByteString a+ | Error Int ByteString+ | Retry ByteString+ deriving (Show)+ data Match = Match { -- Document ID documentId :: Int64@@ -141,6 +183,9 @@ } deriving Show -data Attr = AttrMulti [Int]- | AttrNum Int- deriving Show+data Attr = AttrMulti [Attr]+ | AttrUInt Int+ | AttrBigInt Int64+ | AttrString ByteString+ | AttrFloat Float+ deriving (Show)
sphinx.cabal view
@@ -1,5 +1,5 @@ Name: sphinx-Version: 0.2.1+Version: 0.3.3 Synopsis: Haskell bindings to the Sphinx full-text searching deamon. Description: Haskell bindings to the Sphinx full-text searching deamon. This module is heavily inspired by the php and python client.@@ -8,9 +8,16 @@ License-file: LICENSE Copyright: (c) 2008 Tupil Author: Tupil-Maintainer: Chris Eidhof <ce+sphinx@tupil.com>-Exposed-Modules: Text.Search.Sphinx, Text.Search.Sphinx.Types,- Text.Search.Sphinx.Configuration, Text.Search.Sphinx.Indexable+Maintainer: Greg Weber <greg@gregweber.info>++Exposed-Modules: Text.Search.Sphinx,+ Text.Search.Sphinx.Types,+ Text.Search.Sphinx.Configuration, Text.Search.Sphinx.ExcerptConfiguration, + Text.Search.Sphinx.Indexable+ Other-Modules: Text.Search.Sphinx.Get, Text.Search.Sphinx.Put+ Build-Type: Simple-Build-Depends: base, binary, bytestring, network, haskell98, xml+Build-Depends: base >= 4 && < 5,+ binary, data-binary-ieee754,+ bytestring, network, haskell98, xml