hunt-searchengine-0.3.0.0: src/Hunt/Index/InvertedIndex.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverlappingInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
-- ----------------------------------------------------------------------------
{- |
Top-level index implementations with 'Text' keys for
* text
* integers
* dates and
* geographic positions.
-}
-- ----------------------------------------------------------------------------
module Hunt.Index.InvertedIndex
{-
( InvertedIndex (..)
, InvertedIndexDate
, InvertedIndexInt
, InvertedIndexPosition
, InvertedIndexRTree
)
-- -}
where
import Prelude as P
import Control.DeepSeq
import Data.Bijection.Instances ()
import Data.Binary (Binary (..))
import qualified Data.List as L
import Data.Text (Text)
import qualified Data.Text as T
import Data.Typeable
import Hunt.Common.BasicTypes
import Hunt.Common.Occurrences (Occurrences)
import Hunt.Index as Ix
import Hunt.Index.PrefixTreeIndex
import qualified Hunt.Index.PrefixTreeIndex2Dim as PT2D
import Hunt.Index.Proxy.KeyIndex
-- ------------------------------------------------------------
-- Inverted index using text key
-- ------------------------------------------------------------
-- | Text index using a 'StringMap'-implementation.
newtype InvertedIndex
= InvIx { invIx :: KeyProxyIndex Text (DmPrefixTree Occurrences) }
deriving (Eq, Show, NFData, Typeable)
mkInvIx :: KeyProxyIndex Text (DmPrefixTree Occurrences)
-> InvertedIndex
mkInvIx x = InvIx $! x
-- ------------------------------------------------------------
instance Binary InvertedIndex where
put = put . invIx
get = get >>= return . mkInvIx
-- ------------------------------------------------------------
instance Index InvertedIndex where
type IKey InvertedIndex = Word
type IVal InvertedIndex = Occurrences
insertList wos (InvIx i)
= mkInvIx $ insertList wos i
deleteDocs docIds (InvIx i)
= mkInvIx $ deleteDocs docIds i
empty
= mkInvIx $ empty
fromList l
= mkInvIx $ fromList l
toList (InvIx i)
= toList i
search t k (InvIx i)
= search t k i
-- here the scoring of found word rel. to searched word is added
searchSc t k m
= L.map scoreWord $ search t k m
where
dist
= similar k
scoreWord (w, r)
= (w, (dist w, r))
lookupRange k1 k2 (InvIx i)
= lookupRange k1 k2 i
-- for lookupRangeSc the default scoring (all 1.0) is done
--
-- no better scoring known
unionWith op (InvIx i1) (InvIx i2)
= mkInvIx $ unionWith op i1 i2
{-
unionWithConv to f (InvIx i1) (InvIx i2)
= mkInvIx $ unionWithConv to f i1 i2
-}
map f (InvIx i)
= mkInvIx $ Ix.map f i
mapMaybe f (InvIx i)
= mkInvIx $ Ix.mapMaybe f i
keys (InvIx i)
= keys i
-- ------------------------------------------------------------
-- | a simple similarity heuristic for scoring words found
-- when doing a fuzzy or prefix search
similar :: Text -> Text -> Score
similar s f
= -- traceShow ("similar"::Text, s, f, r) $
r
where
r = similar' s f
similar' :: Text -> Text -> Score
similar' searched found
| searched == found
= 1.0
| ls == lf
= 0.75
| ls < lf -- reduce score by length of found word
= 0.5 * (fromIntegral ls / fromIntegral lf)
| otherwise -- make similar total
= noScore
where
ls = T.length searched
lf = T.length found
-- ------------------------------------------------------------
-- Inverted index using 2-dimensional lookup
-- ------------------------------------------------------------
-- | Text index with 2-dimensional lookup using a 'StringMap'-implementation.
newtype InvertedIndex2Dim
= InvIx2D { invIx2D :: KeyProxyIndex Text (PT2D.DmPrefixTree Occurrences) }
deriving (Eq, Show, NFData, Typeable)
mkInvIx2D :: KeyProxyIndex Text (PT2D.DmPrefixTree Occurrences)
-> InvertedIndex2Dim
mkInvIx2D x = InvIx2D $! x
-- ------------------------------------------------------------
instance Binary InvertedIndex2Dim where
put = put . invIx2D
get = get >>= return . mkInvIx2D
-- ------------------------------------------------------------
instance Index InvertedIndex2Dim where
type IKey InvertedIndex2Dim = Word
type IVal InvertedIndex2Dim = Occurrences
insertList wos (InvIx2D i)
= mkInvIx2D $ insertList wos i
deleteDocs docIds (InvIx2D i)
= mkInvIx2D $ deleteDocs docIds i
empty
= mkInvIx2D $ empty
fromList l
= mkInvIx2D $ fromList l
toList (InvIx2D i)
= toList i
search t k (InvIx2D i)
= search t k i
-- TODO: searchSc and lookupRangeSc implementation similar to InvertedIndexInt and InvertedIndex
lookupRange k1 k2 (InvIx2D i)
= lookupRange k1 k2 i
unionWith op (InvIx2D i1) (InvIx2D i2)
= mkInvIx2D $ unionWith op i1 i2
{-
unionWithConv to f (InvIx2D i1) (InvIx2D i2)
= mkInvIx2D $ unionWithConv to f i1 i2
-}
map f (InvIx2D i)
= mkInvIx2D $ Ix.map f i
mapMaybe f (InvIx2D i)
= mkInvIx2D $ Ix.mapMaybe f i
keys (InvIx2D i)
= keys i