sphinx (empty) → 0.0
raw patch · 4 files changed
+281/−0 lines, 4 filesdep +basedep +binarydep +bytestringsetup-changed
Dependencies added: base, binary, bytestring, haskell98, network
Files
- LICENSE +30/−0
- Setup.lhs +4/−0
- Text/Search/Sphinx.hs +233/−0
- sphinx.cabal +14/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2008, Tupil++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Tupil nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.lhs view
@@ -0,0 +1,4 @@+#! /usr/bin/env runhaskell+ +> import Distribution.Simple+> main = defaultMain
+ Text/Search/Sphinx.hs view
@@ -0,0 +1,233 @@+-- | This is the Haskell version of the Sphinx searchd client.++module Text.Search.Sphinx (Configuration (..), query, defaultConfig) where++import Network+import IO hiding (bracket)+import System+import Control.Exception+import Data.Binary.Get+import Data.Binary.Put+import Data.ByteString.Lazy hiding (pack, length, map)+import Data.ByteString.Lazy.Char8 (pack)+import qualified Data.ByteString.Lazy as BS+import Data.Char (ord, chr)+import Control.Monad+import Data.Int (Int64)+import Prelude hiding (readList)++-- | The configuration for a query+data Configuration = Configuration {+ -- | The hostname of the Sphinx daemon+ host :: String+ -- | The portnumber of the Sphinx daemon+ , port :: PortID+ -- | How many records to seek from result-set start (default is 0)+ , offset :: Int+ -- | How many records to return from result-set starting at offset (default is 20)+ , limit :: Int+ -- | Query matching mode+ , mode :: Int+ -- | Ranking mode+ , ranker :: Int+ -- | Match sorting mode+ , sort :: Int+ -- | Attribute to sort by+ , sortBy :: String+ -- | Minimum ID to match, 0 means no limit+ , minId :: Int+ -- | Maximum ID to match, 0 means no limit+ , maxId :: Int+ -- | Group-by sorting clause (to sort groups in result set with)+ , groupSort :: String+}++data AttributeType = AttrNone + | AttrInteger + | AttrTimestamp + | AttrOrdinal + | AttrBool + | AttrFloat + | AttrMulti++attributeType :: Int -> AttributeType+attributeType 0 = AttrNone+attributeType 1 = AttrInteger+attributeType 2 = AttrTimestamp+attributeType 3 = AttrOrdinal+attributeType 4 = AttrBool+attributeType 5 = AttrFloat+attributeType 0X40000000 = AttrMulti++type Connection = (Handle, Configuration)+++connect :: Configuration -> IO Connection+connect cfg = do connection <- connectTo (host cfg) (port cfg)+ bs <- hGet connection 4+ let version = runGet getWord32be bs+ myVersion = runPut (putWord32be 1)+ hPut connection myVersion+ return (connection, cfg)+ --sClose connection++num = putWord32be . toEnum+num64 = putWord64be . toEnum++numList ls = do num (length ls)+ mapM_ num ls++nums cfg = mapM_ (\x -> num $ x cfg)+num64s cfg = mapM_ (\x -> num64 $ x cfg)++str :: String -> Put+str s = do let bs = pack s+ num (Prelude.length s) -- todo: dangerous+ putLazyByteString bs++addQuery :: Connection -> String -> String -> String -> Put+addQuery c q i cm = addQuery' c q i cm++addQuery' (handle, cfg) query index comment = do+ nums cfg [offset, limit, mode, ranker, sort]+ -- pack sortbyLen and sortBy+ str (sortBy cfg)+ -- pack the queryLen and query encoded in utf-8+ str query+ -- weights+ numList [100, 1]+ -- pack len index and index+ str index+ num 1 -- tODO: id64 range marker+ num64s cfg [minId, maxId]+ -- pack len filters + filters+ num 0 -- todo+ -- pack groupfunc+ num 0 -- todo+ -- pack len groupby + groupby+ str "" --todo+ -- -- req.append ( pack ( '>2L', self._maxmatches) ) )+ nums cfg [const 1000] --todo++ -- -- req.append ( len + self._groupsort )+ str (groupSort cfg)++ -- -- req.append ( pack ( '>LLL', self._cutoff, self._retrycount, self._retrydelay)) + nums cfg [const 0, const 0, const 0]+ -- -- req.append ( self._groupdistinct)+ str "" --todo+ -- -- anchor point+ num 0 --todo+ -- -- per index weights+ num 0 --todo+ -- pack [max_query_time]+ num 0 --todo+ -- -- per-field weights+ num 0 --todo+ -- pack commentLen + comment+ str comment++-- | A basic, default configuration.+defaultConfig = Configuration {+ port = PortNumber 3312+ , host = "127.0.0.1"+ , offset = 0+ , limit = 20+ , mode = sph_match_all+ , ranker = sph_rank_proximity_bm25+ , sort = sort_relevance+ , sortBy = ""+ , minId = 0+ , maxId = 0+ , groupSort = "@group desc"+ }++sph_match_all = 0+sph_rank_proximity_bm25 = 0+sort_relevance = 0++cmdSearch = putWord16be 0+verCmdSearch = putWord16be 0x113++query :: Configuration -> String -> IO [Text.Search.Sphinx.SearchResult]+query config s = do+ conn <- connect config+ let q = addQuery conn s "*" ""+ runQueries (fst conn) q 1++runQueries :: Handle -> Put -> Int -> IO [SearchResult]+runQueries conn q numQueries = do+ let req = runPut (makeRunQuery q numQueries)+ hPut conn req+ hFlush conn+ getResponse conn 1++makeRunQuery query numQueries = do+ cmdSearch+ verCmdSearch+ num $ fromEnum $ BS.length (runPut query) + 4+ num numQueries+ query++--getResponse :: Handle -> Int -> IO [SearchResult]+getResponse conn numResults = do+ bs <- hGet conn 8+ let x@(status, version, len) = runGet f bs+ response <- hGet conn (fromIntegral len)+ return $ runGet (numResults `times` getResult) response+ where+ f = do status <- getWord16be+ version <- getWord16be+ length <- getWord32be+ return (status, version, length)++-- todo applicative+getNum :: Get Int+getNum = getWord32be >>= return . fromEnum++getNum64 :: Get Int64+getNum64 = getWord64be >>= return . fromIntegral++readList f = do num <- getNum+ num `times` f++type SearchResult = ([(Int64, Int, [Int])], Int, Int, Int, [(ByteString, Int, Int)])+getResult :: Get SearchResult+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 $ (matches, total, totalFound, time, wrds)++times = replicateM++readWord = do s <- readStr+ [doc, hits] <- 2 `times` getNum+ return (s, doc, hits)++readField = readStr++readMatch isId64 attrs = do+ doc <- if isId64 then getNum64 else (getNum >>= return . fromIntegral)+ weight <- getNum+ matchAttrs <- mapM readMatchAttr attrs+ return (doc, weight, matchAttrs)++readMatchAttr AttrFloat = error "readMatchAttr for AttrFloat not implemented yet."+readMatchAttr AttrMulti = error "readMatchAttr for AttrFloat not implemented yet."+readMatchAttr _ = getNum+++readStr = do len <- getNum+ getLazyByteString (fromIntegral len)++readAttr = do+ s <- readStr+ t <- getNum+ return (s, attributeType t)
+ sphinx.cabal view
@@ -0,0 +1,14 @@+Name: sphinx+Version: 0.0+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.+Category: Text, Search, Database+License: BSD3+License-file: LICENSE+Copyright: (c) 2008 Tupil+Author: Tupil+Maintainer: Chris Eidhof <ce+sphinx@tupil.com>+Exposed-Modules: Text.Search.Sphinx+Build-Type: Simple+Build-Depends: base, binary, bytestring, network, haskell98