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.Context
29 import Gargantext.Database.Query.Table.NodeNode
30 import Gargantext.Database.Query.Table.NodeContext
31 import Gargantext.Database.Schema.Node
32 import Gargantext.Database.Schema.Context
33 import Gargantext.Prelude
34 import Gargantext.Core.Text.Terms.Mono.Stem.En (stemIt)
35 import Opaleye hiding (Order)
36 import Data.Profunctor.Product (p4)
37 import qualified Opaleye as O hiding (Order)
39 ------------------------------------------------------------------------
40 searchDocInDatabase :: HasDBid NodeType
43 -> Cmd err [(NodeId, HyperdataDocument)]
44 searchDocInDatabase _p t = runOpaQuery (queryDocInDatabase t)
46 -- | Global search query where ParentId is Master Node Corpus Id
47 queryDocInDatabase :: Text -> O.Select (Column SqlInt4, Column SqlJsonb)
48 queryDocInDatabase q = proc () -> do
49 row <- queryNodeSearchTable -< ()
50 restrict -< (_ns_search row) @@ (sqlTSQuery (unpack q))
51 restrict -< (_ns_typename row) .== (sqlInt4 $ toDBid NodeDocument)
52 returnA -< (_ns_id row, _ns_hyperdata row)
54 ------------------------------------------------------------------------
55 -- | todo add limit and offset and order
56 searchInCorpus :: HasDBid NodeType
64 searchInCorpus cId t q o l order = runOpaQuery
65 $ filterWith o l order
70 searchCountInCorpus :: HasDBid NodeType
75 searchCountInCorpus cId t q = runCountOpaQuery
80 queryInCorpus :: HasDBid NodeType
84 -> O.Select FacetDocRead
85 queryInCorpus cId t q = proc () -> do
86 (c, nc) <- joinInCorpus -< ()
87 restrict -< (nc^.nc_node_id) .== (toNullable $ pgNodeId cId)
89 then (nc^.nc_category) .== (toNullable $ sqlInt4 0)
90 else (nc^.nc_category) .>= (toNullable $ sqlInt4 1)
91 restrict -< (c ^. cs_search) @@ (sqlTSQuery (unpack q))
92 restrict -< (c ^. cs_typename ) .== (sqlInt4 $ toDBid NodeDocument)
93 returnA -< FacetDoc { facetDoc_id = c^.cs_id
94 , facetDoc_created = c^.cs_date
95 , facetDoc_title = c^.cs_name
96 , facetDoc_hyperdata = c^.cs_hyperdata
97 , facetDoc_category = nc^.nc_category
98 , facetDoc_ngramCount = nc^.nc_score
99 , facetDoc_score = nc^.nc_score
102 joinInCorpus :: O.Select (ContextSearchRead, NodeContextReadNull)
103 joinInCorpus = leftJoin queryContextSearchTable queryNodeContextTable cond
105 cond :: (ContextSearchRead, NodeContextRead) -> Column SqlBool
106 cond (c, nc) = nc^.nc_context_id .== _cs_id c
108 ------------------------------------------------------------------------
109 searchInCorpusWithContacts
117 -> Cmd err [FacetPaired Int UTCTime HyperdataContact Int]
118 searchInCorpusWithContacts cId aId q o l _order =
119 runOpaQuery $ limit' l
121 $ orderBy ( desc _fp_score)
122 $ selectGroup cId aId
132 ( Column (Nullable SqlInt4)
133 , Column (Nullable SqlTimestamptz)
134 , Column (Nullable SqlJsonb)
135 , Column (Nullable SqlInt4)
137 selectContactViaDoc cId aId q = proc () -> do
138 (doc, (corpus_doc, (_contact_doc, (annuaire_contact, contact)))) <- queryContactViaDoc -< ()
139 restrict -< (doc^.ns_search) @@ (sqlTSQuery $ unpack q )
140 restrict -< (doc^.ns_typename) .== (sqlInt4 $ toDBid NodeDocument)
141 restrict -< (corpus_doc^.nn_node1_id) .== (toNullable $ pgNodeId cId)
142 restrict -< (annuaire_contact^.nn_node1_id) .== (toNullable $ pgNodeId aId)
143 restrict -< (contact^.node_typename) .== (toNullable $ sqlInt4 $ toDBid NodeContact)
144 returnA -< ( contact^.node_id
146 , contact^.node_hyperdata
147 , toNullable $ sqlInt4 1
150 selectGroup :: HasDBid NodeType
154 -> Select FacetPairedReadNull
155 selectGroup cId aId q = proc () -> do
156 (a, b, c, d) <- aggregate (p4 (groupBy, groupBy, groupBy, O.sum))
157 (selectContactViaDoc cId aId q) -< ()
158 returnA -< FacetPaired a b c d
161 queryContactViaDoc :: O.Select ( NodeSearchRead
182 cond12 :: (NodeNodeRead, NodeRead) -> Column SqlBool
183 cond12 (annuaire_contact, contact) = contact^.node_id .== annuaire_contact^.nn_node2_id
185 cond23 :: ( NodeNodeRead
190 cond23 (contact_doc, (annuaire_contact, _)) = contact_doc^.nn_node1_id .== annuaire_contact^.nn_node2_id
192 cond34 :: ( NodeNodeRead
199 cond34 (corpus_doc, (contact_doc, (_,_))) = corpus_doc^.nn_node2_id .== contact_doc^.nn_node2_id
202 cond45 :: ( NodeSearchRead
211 cond45 (doc, (corpus_doc, (_,(_,_)))) = doc^.ns_id .== corpus_doc^.nn_node2_id
214 ------------------------------------------------------------------------