HsHyperEstraier-0.4: Text/HyperEstraier/Condition.hsc
{-# LANGUAGE
EmptyDataDecls
, ForeignFunctionInterface
, UnicodeSyntax
#-}
#include "estraier.h"
{-# OPTIONS_HADDOCK prune #-}
-- |An interface to functions to manipulate search conditions.
module Text.HyperEstraier.Condition
( -- * Types
Condition
, ESTCOND -- private
, CondOption(..)
, SearchSpeed(..)
, SyntaxType(..)
, Eclipse(..)
, withCondPtr -- private
-- * Manipulating conditions
, newCondition
, setPhrase
, addAttrCond
, setOrder
, setMax
, setSkip
, setOptions
, setAuxiliary
, setEclipse
, setDistinct
, setMetaSearchMask
)
where
import Control.Exception
import Data.Bits
import qualified Data.Text as T
import Foreign.C.String
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Ptr
import Prelude.Unicode
import Text.HyperEstraier.Utils
-- |'Condition' is an opaque object representing a search condition.
newtype Condition = Condition (ForeignPtr ESTCOND)
data ESTCOND
-- |'CondOption' is an option to the search condition.
data CondOption
= Speed SearchSpeed -- ^ Choose a @'SearchSpeed'@.
| OmitTFIDF -- ^ Omit calculating TF-IDF weight.
| Syntax SyntaxType -- ^ Choose a @'SyntaxType'@.
deriving (Eq, Show)
-- |'SearchSpeed' is an option to the search condition.
data SearchSpeed
= Slow -- ^ Search for all N-gram keys.
| Normal -- ^ Search for N-gram keys alternately.
| Fast -- ^ Search for N-gram keys by skipping 2\/3 of them.
| EvenFaster -- ^ Search for N-gram keys by skipping 3\/4 of them.
deriving (Eq, Show)
-- |'SyntaxType' is an option to the search condition.
data SyntaxType
= Simplified -- ^ Interpret the condition phrase as the
-- simplified syntax. See the user's guide of the
-- HyperEstraier for explanation about the
-- simplified syntax.
| Rough -- ^ Interpret the condition phrase as the rough
-- syntax. See the user's guide for details.
| Union -- ^ Interpret the condition phrase as the union
-- syntax. See the user's guide for details.
| Intersection -- ^ Interpret the condition phrase as the
-- intersection syntax. See the user's guide for
-- details.
deriving (Eq, Show)
marshalCondOption ∷ CondOption → CInt
marshalCondOption (Speed Slow ) = #const ESTCONDSURE
marshalCondOption (Speed Normal ) = #const ESTCONDUSUAL
marshalCondOption (Speed Fast ) = #const ESTCONDFAST
marshalCondOption (Speed EvenFaster ) = #const ESTCONDAGITO
marshalCondOption OmitTFIDF = #const ESTCONDNOIDF
marshalCondOption (Syntax Simplified ) = #const ESTCONDSIMPLE
marshalCondOption (Syntax Rough ) = #const ESTCONDROUGH
marshalCondOption (Syntax Union ) = #const ESTCONDUNION
marshalCondOption (Syntax Intersection) = #const ESTCONDISECT
-- |'Eclipse' represents how to hide documents from the search
-- result by their similarity.
data Eclipse
= Threshold Double -- ^ Threshold to cause eclipse to
-- documents. @'Threshold' x@ must satisfy
-- @0.0 <= x <= 1.0@.
| ThresholdWithURL Double -- ^ This is similar to @'Threshold'@
-- but this specifies that the document
-- URI is also used to calculate the
-- similarity.
| SameServer -- ^ Cause eclipse to the documents on the same
-- server.
| SameDirectory -- ^ Cause eclipse to the documents in the same
-- directory.
| SameFile -- ^ Cause eclipse to the documents whose file
-- name is the same.
deriving (Eq, Show)
marshalEclipse ∷ Eclipse → CDouble
marshalEclipse (Threshold thr) = assertThreshold (realToFrac thr)
marshalEclipse (ThresholdWithURL thr) = assertThreshold (realToFrac thr) + #const ESTECLSIMURL
marshalEclipse SameServer = #const ESTECLSERV
marshalEclipse SameDirectory = #const ESTECLDIR
marshalEclipse SameFile = #const ESTECLFILE
assertThreshold ∷ (Fractional a, Ord a) ⇒ a → a
assertThreshold thr = assert (thr >= 0.0 && thr <= 1.0) thr
foreign import ccall unsafe "estraier.h est_cond_new"
_new ∷ IO (Ptr ESTCOND)
foreign import ccall unsafe "estraier.h &est_cond_delete"
_delete ∷ FunPtr (Ptr ESTCOND → IO ())
foreign import ccall unsafe "estraier.h est_cond_set_phrase"
_set_phrase ∷ Ptr ESTCOND → CString → IO ()
foreign import ccall unsafe "estraier.h est_cond_add_attr"
_add_attr ∷ Ptr ESTCOND → CString → IO ()
foreign import ccall unsafe "estraier.h est_cond_set_order"
_set_order ∷ Ptr ESTCOND → CString → IO ()
foreign import ccall unsafe "estraier.h est_cond_set_max"
_set_max ∷ Ptr ESTCOND → CInt → IO ()
foreign import ccall unsafe "estraier.h est_cond_set_skip"
_set_skip ∷ Ptr ESTCOND → CInt → IO ()
foreign import ccall unsafe "estraier.h est_cond_set_options"
_set_options ∷ Ptr ESTCOND → CInt → IO ()
foreign import ccall unsafe "estraier.h est_cond_set_auxiliary"
_set_auxiliary ∷ Ptr ESTCOND → CInt → IO ()
foreign import ccall unsafe "estraier.h est_cond_set_eclipse"
_set_eclipse ∷ Ptr ESTCOND → CDouble → IO ()
foreign import ccall unsafe "estraier.h est_cond_set_distinct"
_set_distinct ∷ Ptr ESTCOND → CString → IO ()
foreign import ccall unsafe "estraier.h est_cond_set_mask"
_set_mask ∷ Ptr ESTCOND → CInt → IO ()
wrapCond ∷ Ptr ESTCOND → IO Condition
wrapCond = fmap Condition ∘ newForeignPtr _delete
withCondPtr ∷ Condition → (Ptr ESTCOND → IO a) → IO a
withCondPtr (Condition cond) = withForeignPtr cond
-- |'newCondition' creates an empty search condition.
newCondition ∷ IO Condition
newCondition = _new >>= wrapCond
-- |@'setPhrase' cond phrase@ stores a condition phrase into
-- @cond@. The syntax of the phrase is assumed to be the normal
-- syntax, unless you specify a 'SyntaxType' explicitly with
-- 'setOptions'.
setPhrase ∷ Condition → T.Text → IO ()
setPhrase cond phrase
= withCondPtr cond $ \ condPtr →
withUTF8CString phrase $
_set_phrase condPtr
-- |@'addAttrCond' cond expr@ appends an attribute search condition to
-- @cond@. See the user's guide for explanation about the attribute
-- search condition.
addAttrCond ∷ Condition → T.Text → IO ()
addAttrCond cond attr
= withCondPtr cond $ \ condPtr →
withUTF8CString attr $
_add_attr condPtr
-- |@'setOrder' cond expr@ stores an ordering expression into
-- @cond@. See the user's guide for explanation about the ordering
-- expression. By default, the result is sorted in descending order of
-- score.
setOrder ∷ Condition → T.Text → IO ()
setOrder cond order
= withCondPtr cond $ \ condPtr →
withUTF8CString order $
_set_order condPtr
-- |@'setMax' cond n@ specifies the maximum number of results. By
-- default, the number of results is unlimited.
setMax ∷ Condition → Int → IO ()
setMax cond
= withCondPtr cond ∘ flip _set_max ∘ fromIntegral
-- |@'setSkip' cond n@ specifies how many documents should be skipped
-- from the beginning of result.
setSkip ∷ Condition → Int → IO ()
setSkip cond
= withCondPtr cond ∘ flip _set_skip ∘ fromIntegral
-- |@'setOptions' cond opts@ specifies options to the search
-- condition.
setOptions ∷ Condition → [CondOption] → IO ()
setOptions cond
= withCondPtr cond .
flip _set_options .
marshalOpts marshalCondOption
-- |@'setAuxiliary' cond min@ specifies how many documents should be
-- in the result to avoid using the auxiliary index to pad the result.
setAuxiliary ∷ Condition → Int → IO ()
setAuxiliary cond
= withCondPtr cond ∘ flip _set_auxiliary ∘ fromIntegral
-- |@'setEclipse' cond ecl@ specifies how to hide documents from the
-- search result by their similarity.
setEclipse ∷ Condition → Eclipse → IO ()
setEclipse cond
= withCondPtr cond ∘ flip _set_eclipse ∘ marshalEclipse
-- |@'setDistinct' cond attr@ specifies an attribute which must be
-- unique to the search result.
setDistinct ∷ Condition → T.Text → IO ()
setDistinct cond attr
= withCondPtr cond $ \ condPtr →
withUTF8CString attr $
_set_distinct condPtr
-- |@'setMetaSearchMask' cond xs@ specifies that, in
-- 'Text.HyperEstraier.Database.metaSearch', some databases must be
-- excluded from the search result. e.g.
--
-- > main = withDatabase "db1" (Reader []) $ \ db1 →
-- > withDatabase "db2" (Reader []) $ \ db2 →
-- > withDatabase "db3" (Reader []) $ \ db3 →
-- > do cond <- newCondition
-- > setPhrase cond "hello AND world"
-- > setMetaSearchMask cond [0, 2] -- zero-origin
-- >
-- > -- In this case, "db1" and "db3" are excluded from the meta search.
-- > result <- metaSearch [db1, db2, db3]
-- > print result
--
setMetaSearchMask ∷ Condition → [Int] → IO ()
setMetaSearchMask cond
= withCondPtr cond ∘ flip _set_max ∘ fromIntegral ∘ calculateMask
where
calculateMask ∷ [Int] → Int
calculateMask [] = 0
calculateMask (y:ys) = assert (y >= 0 && y <= 28)
$ (1 `shiftL` y) .|. calculateMask ys