packages feed

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 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