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 all') <> (toElements CandidateTerm all')
77 --pure $ (toElements GraphTerm $ take 10 all') <> (toElements CandidateTerm $ drop 10 all')
79 toElements nType x = Map.fromList [(nt, [ mkNgramsElement t nType Nothing (mSetFromList [])
86 buildNgramsTermsList' :: UserCorpusId
88 -> ((Text, (Set Text, Set NodeId)) -> Bool) -> Int -> Int
89 -> Cmd err (Map NgramsType [NgramsElement])
91 buildNgramsTermsList' uCid groupIt stop gls is = do
92 ngs <- groupNodesByNgramsWith groupIt <$> getNodesByNgramsUser uCid NgramsTerms
95 (stops, candidates) = partitionEithers
96 $ map (\t -> if stop t then Left t else Right t)
98 $ Map.filter ((\s' -> Set.size s' > 1) . snd) ngs
100 (maps, candidates') = takeScored gls is
101 $ getCoocByNgrams' snd (Diagonal True)
102 $ Map.fromList candidates
105 toList' t = (fst t, (fromIntegral $ Set.size $ snd $ snd t, fst $ snd t))
108 , List.filter (\(k,_) -> List.elem k candidates') candidates
109 , List.filter (\(k,_) -> List.elem k maps) candidates
112 let ngs' = List.concat
113 $ map toNgramsElement
114 $ map (\t -> (StopTerm, toList' t)) s
115 <> map (\t -> (CandidateTerm, toList' t)) c
116 <> map (\t -> (GraphTerm, toList' t)) m
118 pure $ Map.fromList [(NgramsTerms, ngs')]
121 buildNgramsTermsList :: Lang -> Int -> Int -> StopSize -> UserCorpusId -> MasterCorpusId
122 -> Cmd err (Map NgramsType [NgramsElement])
123 buildNgramsTermsList l n m s uCid mCid = do
124 candidates <- sortTficf <$> getTficf' uCid mCid NgramsTerms (ngramsGroup l n m)
126 candidatesSize = 2000
129 candidatesHead = List.take candidatesSize candidates
130 candidatesTail = List.drop candidatesSize candidates
131 termList = (toTermList a b ((isStopTerm s) . fst) candidatesHead)
132 <> (map (toList ((isStopTerm s) .fst) CandidateTerm) candidatesTail)
133 let ngs = List.concat $ map toNgramsElement termList
135 pure $ Map.fromList [(NgramsTerms, ngs)]
138 toNgramsElement :: (ListType, (Text, (Double, Set Text))) -> [NgramsElement]
139 toNgramsElement (listType, (_stem, (_score, setNgrams))) =
140 case Set.toList setNgrams of
142 (parent:children) -> [parentElem] <> childrenElems
144 parentElem = mkNgramsElement parent
147 (mSetFromList children)
148 childrenElems = map (\t -> mkNgramsElement t listType
149 (Just $ RootParent parent parent)
154 toList :: (b -> Bool) -> ListType -> b -> (ListType, b)
155 toList stop l n = case stop n of
156 True -> (StopTerm, n)
160 toTermList :: Int -> Int -> (a -> Bool) -> [a] -> [(ListType, a)]
161 toTermList _ _ _ [] = []
162 toTermList a b stop ns = trace ("computing toTermList") $
163 map (toList stop CandidateTerm) xs
164 <> map (toList stop GraphTerm) ys
165 <> toTermList a b stop zs
174 isStopTerm :: StopSize -> Text -> Bool
175 isStopTerm (StopSize n) x = Text.length x < n || any isStopChar (Text.unpack x)
177 isStopChar c = not (c `elem` ("- /()%" :: [Char]) || Char.isAlpha c)