2 Module : Gargantext.Text.Ngrams.Lists
3 Description : Tools to build lists
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
12 {-# LANGUAGE NoImplicitPrelude #-}
13 {-# LANGUAGE OverloadedStrings #-}
14 {-# LANGUAGE RankNTypes #-}
16 module Gargantext.Text.List
19 import Data.Either (partitionEithers, Either(..))
20 import Debug.Trace (trace)
23 import Data.Text (Text)
24 import Gargantext.API.Ngrams (NgramsElement, mkNgramsElement, RootParent(..), mSetFromList)
25 import Gargantext.API.Ngrams.Tools (getCoocByNgrams', Diagonal(..))
26 import Gargantext.Core (Lang(..))
27 import Gargantext.Core.Types (ListType(..), MasterCorpusId, UserCorpusId, NodeId)
28 import Gargantext.Database.Metrics.NgramsByNode (getTficf', sortTficf, ngramsGroup, getNodesByNgramsUser, groupNodesByNgramsWith)
29 import Gargantext.Database.Schema.Ngrams (NgramsType(..))
30 import Gargantext.Database.Utils (Cmd)
31 import Gargantext.Text.List.Learn (Model(..))
32 import Gargantext.Text.Metrics (takeScored)
33 import Gargantext.Prelude
34 --import Gargantext.Text.Terms (TermType(..))
35 import qualified Data.Char as Char
36 import qualified Data.List as List
37 import qualified Data.Map as Map
38 import qualified Data.Set as Set
39 import qualified Data.Text as Text
42 data NgramsListBuilder = BuilderStepO { stemSize :: Int
46 | BuilderStep1 { withModel :: Model }
47 | BuilderStepN { withModel :: Model }
48 | Tficf { nlb_lang :: Lang
51 , nlb_stopSize :: StopSize
52 , nlb_userCorpusId :: UserCorpusId
53 , nlb_masterCorpusId :: MasterCorpusId
57 data StopSize = StopSize {unStopSize :: Int}
59 -- | TODO improve grouping functions of Authors, Sources, Institutes..
60 buildNgramsLists :: Lang -> Int -> Int -> StopSize -> UserCorpusId -> MasterCorpusId
61 -> Cmd err (Map NgramsType [NgramsElement])
62 buildNgramsLists l n m s uCid _mCid = do
63 --ngTerms <- buildNgramsTermsList l n m s uCid mCid
64 ngTerms <- buildNgramsTermsList' uCid (ngramsGroup l n m) (isStopTerm s . fst) 500 50
65 othersTerms <- mapM (buildNgramsOthersList uCid identity) [Authors, Sources, Institutes]
66 pure $ Map.unions $ othersTerms <> [ngTerms]
69 buildNgramsOthersList :: UserCorpusId -> (Text -> Text) -> NgramsType
70 -> Cmd err (Map NgramsType [NgramsElement])
71 buildNgramsOthersList uCid groupIt nt = do
72 ngs <- groupNodesByNgramsWith groupIt <$> getNodesByNgramsUser uCid nt
76 pure $ (toElements GraphTerm $ take 10 all') <> (toElements CandidateTerm $ drop 10 all')
78 toElements nType x = Map.fromList [(nt, [ mkNgramsElement t nType Nothing (mSetFromList [])
85 buildNgramsTermsList' :: UserCorpusId
87 -> ((Text, (Set Text, Set NodeId)) -> Bool) -> Int -> Int
88 -> Cmd err (Map NgramsType [NgramsElement])
90 buildNgramsTermsList' uCid groupIt stop gls is = do
91 ngs <- groupNodesByNgramsWith groupIt <$> getNodesByNgramsUser uCid NgramsTerms
94 (stops, candidates) = partitionEithers
95 $ map (\t -> if stop t then Left t else Right t)
97 $ Map.filter ((\s' -> Set.size s' > 1) . snd) ngs
99 (maps, candidates') = takeScored gls is
100 $ getCoocByNgrams' snd (Diagonal True)
101 $ Map.fromList candidates
104 toList' t = (fst t, (fromIntegral $ Set.size $ snd $ snd t, fst $ snd t))
107 , List.filter (\(k,_) -> List.elem k candidates') candidates
108 , List.filter (\(k,_) -> List.elem k maps) candidates
111 let ngs' = List.concat
112 $ map toNgramsElement
113 $ map (\t -> (StopTerm, toList' t)) s
114 <> map (\t -> (CandidateTerm, toList' t)) c
115 <> map (\t -> (GraphTerm, toList' t)) m
117 pure $ Map.fromList [(NgramsTerms, ngs')]
120 buildNgramsTermsList :: Lang -> Int -> Int -> StopSize -> UserCorpusId -> MasterCorpusId
121 -> Cmd err (Map NgramsType [NgramsElement])
122 buildNgramsTermsList l n m s uCid mCid = do
123 candidates <- sortTficf <$> getTficf' uCid mCid NgramsTerms (ngramsGroup l n m)
125 candidatesSize = 2000
128 candidatesHead = List.take candidatesSize candidates
129 candidatesTail = List.drop candidatesSize candidates
130 termList = (toTermList a b ((isStopTerm s) . fst) candidatesHead)
131 <> (map (toList ((isStopTerm s) .fst) CandidateTerm) candidatesTail)
132 let ngs = List.concat $ map toNgramsElement termList
134 pure $ Map.fromList [(NgramsTerms, ngs)]
137 toNgramsElement :: (ListType, (Text, (Double, Set Text))) -> [NgramsElement]
138 toNgramsElement (listType, (_stem, (_score, setNgrams))) =
139 case Set.toList setNgrams of
141 (parent:children) -> [parentElem] <> childrenElems
143 parentElem = mkNgramsElement parent
146 (mSetFromList children)
147 childrenElems = map (\t -> mkNgramsElement t listType
148 (Just $ RootParent parent parent)
153 toList :: (b -> Bool) -> ListType -> b -> (ListType, b)
154 toList stop l n = case stop n of
155 True -> (StopTerm, n)
159 toTermList :: Int -> Int -> (a -> Bool) -> [a] -> [(ListType, a)]
160 toTermList _ _ _ [] = []
161 toTermList a b stop ns = trace ("computing toTermList") $
162 map (toList stop CandidateTerm) xs
163 <> map (toList stop GraphTerm) ys
164 <> toTermList a b stop zs
173 isStopTerm :: StopSize -> Text -> Bool
174 isStopTerm (StopSize n) x = Text.length x < n || any isStopChar (Text.unpack x)
176 isStopChar c = not (c `elem` ("- /()%" :: [Char]) || Char.isAlpha c)