2 Module : Gargantext.Database.Schema.NodeNgramsNgrams
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
10 NodeNgramsNgrams table is used to group Ngrams
12 - NgramId_1, NgramId_2 where all NgramId_2 will be added to NgramId_1
13 - weight: probability of the relation (TODO, fixed to 1 for simple stemming)
16 - recursive queries of postgres
17 - group with: https://en.wikipedia.org/wiki/Nested_set_model
21 {-# LANGUAGE Arrows #-}
22 {-# LANGUAGE FlexibleInstances #-}
23 {-# LANGUAGE FunctionalDependencies #-}
24 {-# LANGUAGE MultiParamTypeClasses #-}
25 {-# LANGUAGE NoImplicitPrelude #-}
26 {-# LANGUAGE OverloadedStrings #-}
27 {-# LANGUAGE QuasiQuotes #-}
28 {-# LANGUAGE RankNTypes #-}
29 {-# LANGUAGE TemplateHaskell #-}
30 {-# OPTIONS_GHC -fno-warn-orphans #-}
32 module Gargantext.Database.Schema.NodeNgramsNgrams
35 import Control.Lens (view)
36 import Control.Lens.TH (makeLensesWith, abbreviatedFields)
37 import Control.Monad.IO.Class (liftIO)
38 import Data.Text (Text)
39 import Data.Maybe (Maybe)
40 import Data.Profunctor.Product.TH (makeAdaptorAndInstance)
41 import Database.PostgreSQL.Simple.SqlQQ (sql)
42 import Database.PostgreSQL.Simple.Types (Values(..), QualifiedIdentifier(..))
43 import Gargantext.Database.Utils (Cmd, runOpaQuery, runPGSQuery, connection)
44 import Gargantext.Prelude
46 import qualified Database.PostgreSQL.Simple as PGS
48 data NodeNgramsNgramsPoly node_id ngram1_id ngram2_id weight =
49 NodeNgramsNgrams { _nng_NodeId :: node_id
50 , _nng_Ngram1Id :: ngram1_id
51 , _nng_Ngram2Id :: ngram2_id
52 , _nng_Weight :: weight
56 type NodeNgramsNgramsWrite =
57 NodeNgramsNgramsPoly (Column PGInt4 )
60 (Maybe (Column PGFloat8))
62 type NodeNgramsNgramsRead =
63 NodeNgramsNgramsPoly (Column PGInt4 )
68 type NodeNgramsNgrams =
69 NodeNgramsNgramsPoly Int
74 $(makeAdaptorAndInstance "pNodeNgramsNgrams"
75 ''NodeNgramsNgramsPoly)
76 $(makeLensesWith abbreviatedFields
77 ''NodeNgramsNgramsPoly)
80 nodeNgramsNgramsTable :: Table NodeNgramsNgramsWrite NodeNgramsNgramsRead
81 nodeNgramsNgramsTable =
82 Table "nodes_ngrams_ngrams"
83 ( pNodeNgramsNgrams NodeNgramsNgrams
84 { _nng_NodeId = required "node_id"
85 , _nng_Ngram1Id = required "ngram1_id"
86 , _nng_Ngram2Id = required "ngram2_id"
87 , _nng_Weight = optional "weight"
91 queryNodeNgramsNgramsTable :: Query NodeNgramsNgramsRead
92 queryNodeNgramsNgramsTable = queryTable nodeNgramsNgramsTable
94 -- | Select NodeNgramsNgrams
95 -- TODO not optimized (get all ngrams without filters)
96 nodeNgramsNgrams :: Cmd err [NodeNgramsNgrams]
97 nodeNgramsNgrams = runOpaQuery queryNodeNgramsNgramsTable
99 instance QueryRunnerColumnDefault PGInt4 (Maybe Int) where
100 queryRunnerColumnDefault = fieldQueryRunnerColumn
102 instance QueryRunnerColumnDefault PGFloat8 (Maybe Double) where
103 queryRunnerColumnDefault = fieldQueryRunnerColumn
106 -- TODO: Add option on conflict
107 insertNodeNgramsNgramsNew :: [NodeNgramsNgrams] -> Cmd err Int
108 insertNodeNgramsNgramsNew = insertNodeNgramsNgramsW
109 . map (\(NodeNgramsNgrams n ng1 ng2 maybeWeight) ->
110 NodeNgramsNgrams (pgInt4 n )
113 (pgDouble <$> maybeWeight)
116 insertNodeNgramsNgramsW :: [NodeNgramsNgramsWrite] -> Cmd err Int
117 insertNodeNgramsNgramsW ns = do
119 liftIO $ fromIntegral <$> runInsertMany c nodeNgramsNgramsTable ns
121 ------------------------------------------------------------------------
122 data Action = Del | Add
124 type NgramsParent = Text
125 type NgramsChild = Text
127 ngramsGroup' :: Action -> [(Int, NgramsParent, NgramsChild, Maybe Double)]
129 ngramsGroup' action ngs = runNodeNgramsNgrams q ngs
132 Del -> queryDelNodeNgramsNgrams
133 Add -> queryInsertNodeNgramsNgrams
136 runNodeNgramsNgrams :: PGS.Query -> [(Int, NgramsParent, NgramsChild, Maybe Double)] -> Cmd err [Int]
137 runNodeNgramsNgrams q ngs = map (\(PGS.Only a) -> a) <$> runPGSQuery q (PGS.Only $ Values fields ngs' )
139 ngs' = map (\(n,ng1,ng2,w) -> (n,ng1,ng2,maybe 0 identity w)) ngs
140 fields = map (\t -> QualifiedIdentifier Nothing t)
141 ["int4","text","text","double"]
143 --------------------------------------------------------------------
144 -- TODO: on conflict update weight
145 queryInsertNodeNgramsNgrams :: PGS.Query
146 queryInsertNodeNgramsNgrams = [sql|
147 WITH input_rows(nId,ng1,ng2,w) AS (?)
148 INSERT INTO nodes_ngrams_ngrams (node_id,ngram1_id,ngram2_id,weight)
149 SELECT nId,ngrams1.id,ngrams2.id,w FROM input_rows
150 JOIN ngrams ngrams1 ON ngrams1.terms = ng1
151 JOIN ngrams ngrams2 ON ngrams2.terms = ng2
152 ON CONFLICT (node_id,ngram1_id,ngram2_id) DO NOTHING -- unique index created here
155 queryDelNodeNgramsNgrams :: PGS.Query
156 queryDelNodeNgramsNgrams = [sql|
157 WITH input(nId,ng1,ng2,w) AS (?)
158 DELETE FROM nodes_ngrams_ngrams nnn
159 JOIN ngrams ngrams1 ON ngrams.terms = ng1
160 JOIN ngrams ngrams2 ON ngrams.terms = ng2
161 WHERE nnn.node_id = input.nId
162 AND nnn.ngram1_id = ngrams1.id
163 AND nnn.ngram2_id = ngrams2.id