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 (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.Select (Column SqlInt4, Column SqlJsonb)
45 queryDocInDatabase q = proc () -> do
46 row <- queryNodeSearchTable -< ()
47 restrict -< (_ns_search row) @@ (sqlTSQuery (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.Select 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) @@ (sqlTSQuery (unpack q))
89 restrict -< (n ^. ns_typename ) .== (sqlInt4 $ toDBid NodeDocument)
90 returnA -< FacetDoc { facetDoc_id = n^.ns_id
91 , facetDoc_created = n^.ns_date
92 , facetDoc_title = n^.ns_name
93 , facetDoc_hyperdata = n^.ns_hyperdata
94 , facetDoc_category = nn^.nn_category
95 , facetDoc_ngramCount = nn^.nn_score
96 , facetDoc_score = nn^.nn_score
99 joinInCorpus :: O.Select (NodeSearchRead, NodeNodeReadNull)
100 joinInCorpus = leftJoin queryNodeSearchTable queryNodeNodeTable cond
102 cond :: (NodeSearchRead, NodeNodeRead) -> Column SqlBool
103 cond (n, nn) = nn^.nn_node2_id .== _ns_id n
105 ------------------------------------------------------------------------
106 searchInCorpusWithContacts
114 -> Cmd err [FacetPaired Int UTCTime HyperdataContact Int]
115 searchInCorpusWithContacts cId aId q o l _order =
116 runOpaQuery $ limit' l
118 $ orderBy ( desc _fp_score)
119 $ selectGroup cId aId
129 ( Column (Nullable SqlInt4)
130 , Column (Nullable SqlTimestamptz)
131 , Column (Nullable SqlJsonb)
132 , Column (Nullable SqlInt4)
134 selectContactViaDoc cId aId q = proc () -> do
135 (doc, (corpus_doc, (_contact_doc, (annuaire_contact, contact)))) <- queryContactViaDoc -< ()
136 restrict -< (doc^.ns_search) @@ (sqlTSQuery $ unpack q )
137 restrict -< (doc^.ns_typename) .== (sqlInt4 $ toDBid NodeDocument)
138 restrict -< (corpus_doc^.nn_node1_id) .== (toNullable $ pgNodeId cId)
139 restrict -< (annuaire_contact^.nn_node1_id) .== (toNullable $ pgNodeId aId)
140 restrict -< (contact^.node_typename) .== (toNullable $ sqlInt4 $ toDBid NodeContact)
141 returnA -< ( contact^.node_id
143 , contact^.node_hyperdata
144 , toNullable $ sqlInt4 1
147 selectGroup :: HasDBid NodeType
151 -> Select FacetPairedReadNull
152 selectGroup cId aId q = proc () -> do
153 (a, b, c, d) <- aggregate (p4 (groupBy, groupBy, groupBy, O.sum))
154 (selectContactViaDoc cId aId q) -< ()
155 returnA -< FacetPaired a b c d
158 queryContactViaDoc :: O.Select ( NodeSearchRead
179 cond12 :: (NodeNodeRead, NodeRead) -> Column SqlBool
180 cond12 (annuaire_contact, contact) = contact^.node_id .== annuaire_contact^.nn_node2_id
182 cond23 :: ( NodeNodeRead
187 cond23 (contact_doc, (annuaire_contact, _)) = contact_doc^.nn_node1_id .== annuaire_contact^.nn_node2_id
189 cond34 :: ( NodeNodeRead
196 cond34 (corpus_doc, (contact_doc, (_,_))) = corpus_doc^.nn_node2_id .== contact_doc^.nn_node2_id
199 cond45 :: ( NodeSearchRead
208 cond45 (doc, (corpus_doc, (_,(_,_)))) = doc^.ns_id .== corpus_doc^.nn_node2_id
211 ------------------------------------------------------------------------