2 Module : Gargantext.Database.TextSearch
3 Description : Postgres text search experimentation
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
11 {-# LANGUAGE Arrows #-}
13 module Gargantext.Database.Action.Search where
15 import Control.Arrow (returnA)
16 import Control.Lens ((^.))
18 import Data.Text (Text, unpack, intercalate)
19 import Data.Time (UTCTime)
20 import Gargantext.Core
21 import Gargantext.Core.Types
22 import Gargantext.Database.Admin.Types.Hyperdata (HyperdataDocument(..), HyperdataContact(..))
23 import Gargantext.Database.Prelude (Cmd, runOpaQuery, runCountOpaQuery)
24 import Gargantext.Database.Query.Facet
25 import Gargantext.Database.Query.Filter
26 import Gargantext.Database.Query.Join (leftJoin5)
27 import Gargantext.Database.Query.Table.Node
28 import Gargantext.Database.Query.Table.NodeNode
29 import Gargantext.Database.Schema.Node
30 import Gargantext.Prelude
31 import Gargantext.Core.Text.Terms.Mono.Stem.En (stemIt)
32 import Opaleye hiding (Query, Order)
33 import Data.Profunctor.Product (p4)
34 import qualified Opaleye as O hiding (Order)
36 ------------------------------------------------------------------------
37 searchDocInDatabase :: HasDBid NodeType
40 -> Cmd err [(NodeId, HyperdataDocument)]
41 searchDocInDatabase _p t = runOpaQuery (queryDocInDatabase t)
43 -- | Global search query where ParentId is Master Node Corpus Id
44 queryDocInDatabase :: Text -> O.Query (Column PGInt4, Column PGJsonb)
45 queryDocInDatabase q = proc () -> do
46 row <- queryNodeSearchTable -< ()
47 restrict -< (_ns_search row) @@ (pgTSQuery (unpack q))
48 restrict -< (_ns_typename row) .== (sqlInt4 $ toDBid NodeDocument)
49 returnA -< (_ns_id row, _ns_hyperdata row)
51 ------------------------------------------------------------------------
52 -- | todo add limit and offset and order
53 searchInCorpus :: HasDBid NodeType
61 searchInCorpus cId t q o l order = runOpaQuery
62 $ filterWith o l order
67 searchCountInCorpus :: HasDBid NodeType
72 searchCountInCorpus cId t q = runCountOpaQuery
77 queryInCorpus :: HasDBid NodeType
81 -> O.Query FacetDocRead
82 queryInCorpus cId t q = proc () -> do
83 (n, nn) <- joinInCorpus -< ()
84 restrict -< (nn^.nn_node1_id) .== (toNullable $ pgNodeId cId)
86 then (nn^.nn_category) .== (toNullable $ sqlInt4 0)
87 else (nn^.nn_category) .>= (toNullable $ sqlInt4 1)
88 restrict -< (n ^. ns_search) @@ (pgTSQuery (unpack q))
89 restrict -< (n ^. ns_typename ) .== (sqlInt4 $ toDBid NodeDocument)
90 returnA -< FacetDoc (n^.ns_id )
98 joinInCorpus :: O.Query (NodeSearchRead, NodeNodeReadNull)
99 joinInCorpus = leftJoin queryNodeSearchTable queryNodeNodeTable cond
101 cond :: (NodeSearchRead, NodeNodeRead) -> Column PGBool
102 cond (n, nn) = nn^.nn_node2_id .== _ns_id n
104 ------------------------------------------------------------------------
105 searchInCorpusWithContacts
113 -> Cmd err [FacetPaired Int UTCTime HyperdataContact Int]
114 searchInCorpusWithContacts cId aId q o l _order =
115 runOpaQuery $ limit' l
117 $ orderBy ( desc _fp_score)
118 $ selectGroup cId aId
128 ( Column (Nullable PGInt4)
129 , Column (Nullable PGTimestamptz)
130 , Column (Nullable PGJsonb)
131 , Column (Nullable PGInt4)
133 selectContactViaDoc cId aId q = proc () -> do
134 (doc, (corpus_doc, (_contact_doc, (annuaire_contact, contact)))) <- queryContactViaDoc -< ()
135 restrict -< (doc^.ns_search) @@ (pgTSQuery $ unpack q )
136 restrict -< (doc^.ns_typename) .== (sqlInt4 $ toDBid NodeDocument)
137 restrict -< (corpus_doc^.nn_node1_id) .== (toNullable $ pgNodeId cId)
138 restrict -< (annuaire_contact^.nn_node1_id) .== (toNullable $ pgNodeId aId)
139 restrict -< (contact^.node_typename) .== (toNullable $ sqlInt4 $ toDBid NodeContact)
140 returnA -< ( contact^.node_id
142 , contact^.node_hyperdata
143 , toNullable $ sqlInt4 1
146 selectGroup :: HasDBid NodeType
150 -> Select FacetPairedReadNull
151 selectGroup cId aId q = proc () -> do
152 (a, b, c, d) <- aggregate (p4 (groupBy, groupBy, groupBy, O.sum))
153 (selectContactViaDoc cId aId q) -< ()
154 returnA -< FacetPaired a b c d
157 queryContactViaDoc :: O.Query ( NodeSearchRead
178 cond12 :: (NodeNodeRead, NodeRead) -> Column PGBool
179 cond12 (annuaire_contact, contact) = contact^.node_id .== annuaire_contact^.nn_node2_id
181 cond23 :: ( NodeNodeRead
186 cond23 (contact_doc, (annuaire_contact, _)) = contact_doc^.nn_node1_id .== annuaire_contact^.nn_node2_id
188 cond34 :: ( NodeNodeRead
195 cond34 (corpus_doc, (contact_doc, (_,_))) = corpus_doc^.nn_node2_id .== contact_doc^.nn_node2_id
198 cond45 :: ( NodeSearchRead
207 cond45 (doc, (corpus_doc, (_,(_,_)))) = doc^.ns_id .== corpus_doc^.nn_node2_id
210 ------------------------------------------------------------------------