Browse Source

funzioni fe aggiornate

Leonardo Canova 2 years ago
parent
commit
92cd234b91

+ 2 - 1
.gitignore

@@ -2,4 +2,5 @@
 TIgrO
 */.DS_Store
 .vscode/*
-flask_be/engine/__pycache__/*
+flask_be/engine/__pycache__/*
+Progetto2023_BE.log

+ 131 - 20
flask_be/engine/basic_queries.py

@@ -1,29 +1,11 @@
 #%%
-import unicodedata
-from .parsing_utilities import interpreter
+from .parsing_utilities import interpreter, inizialeraddoppiata, list_normalize
 
 # Basic data provider class; can be instantiated to handle different kinds
 # of data-providing connections or interfaces based on config options
 from .data_interface.data_providers_setup import queryHandlerFactory
 
-
-# Utility functions -- possibly to move to parsing_utilities
-
-# %% funzione iniziale raddoppiata, è chiamata dalle funzioni di ricerca con iniziale raddoppiata
-def inizialeraddoppiata (data):
-    doubleddata=[]
-    for el in data:
-        if el[1] != "%" and "_":
-            doubleddata = doubleddata + ["'"+ el[1] + el[1:]]
-    return doubleddata
-
-# %% funzione normalizza stringa (ricerca espansa), è chiamata dalle funzioni di ricerca espansa
-def normalize(stringa):
-    return unicodedata.normalize('NFKD', stringa).encode('ASCII', 'ignore').decode('utf-8')
-
-def list_normalize(lista):
-    return [normalize(stringa) for stringa in lista]
-
+import pandas as pd
 
 # Main class for basic queries contains:
 # - a data provider instance
@@ -32,6 +14,7 @@ class basicQueries:
 
     def __init__(self, dataConfig):
         self.queryHandler = queryHandlerFactory(dataConfig)
+        self.listOcc = dataConfig['listOcc']
 
     # Prepares and sends query OBJECTS which will be processed by the data provider
     def sendBasicQuery(self, text, queryType, espansa, raddoppiata, pandas=False, dbFile=None):
@@ -48,4 +31,132 @@ class basicQueries:
             dataNorm = entries + list_normalize(inizialeraddoppiata(entries))
 
         return self.queryHandler.query({'data': data, 'dataNorm': dataNorm, 'queryType': queryType}, pandas, dbFile)
+    
+    #%% ha in input le funzioni di ricerca, cerca nell'occorrenziario i puntatori ai contesti e altri elementi ad essi associati. 
+    #l'attributo type definisce il tipo di ricerca in input (0 per forme, 1 per lemmi, 2 per lemmi con opzione "mostra occorrenze non lemmatizzate")
+    def findtexts(self, type, df, index = None):
+        if index is None:
+            df = pd.DataFrame(df)
+        else:
+            if isinstance(index, range):
+                index = list(index)
+            elif not isinstance(index, list):
+                index = [index]
+            df = pd.DataFrame(df.loc[index])
+        textlist = pd.DataFrame()
+        codList = list(df["cod"])
+        listOcc = self.listOcc
+        
+        queryData = {'queryType': 'texts', 'querySubtype': type, 'codList': codList}
+
+        for table in listOcc:
+            queryData['table'] = table
+            if type==2:
+                subQueryData = {'queryType': 'pfl', 'codList': codList}
+                subdf = self.queryHandler.query(subQueryData, pandas=True)
+                queryData['formCodList'] = list(subdf["forma"])
+
+            extendequeryReponse = self.queryHandler.query(queryData, pandas=True)
+
+            textlist = pd.concat([textlist, extendequeryReponse])
+
+        return textlist
+
+    # %% ha in input findtexts, restituisce i contesti associati agli elementi localizzati.
+    # Il range dei contesti è impostato di default a 30 parole e può essere rimodulato nel passaggio al contesto singolo.
+
+    def findcontexts(self, textlist):
+        parole = 31
+        listOcc = self.listOcc
+        contexts = []
+        for ind, row in textlist.iterrows():
+            sigla = row["sigla"]
+            queryData = {'queryType': 'contexts', 'ntxlocal': row["ntx"], 'mappalocal': row['mappa'], 'parole': parole}
+            pointerlist = pd.DataFrame()
+            for table in listOcc:
+                queryData['table'] = table
+                queryresponse = self.queryHandler.query(queryData, pandas=True)
+                pointerlist = pd.concat([pointerlist, queryresponse])
+            
+            fileQueryData = {'sigla': sigla, 'minChar': pointerlist["pitxt"].min(), 'maxChar': pointerlist["pitxt"].max()}
+            cont = self.queryHandler.textQuery(fileQueryData)
+            contexts.append(cont)
+        textlist['contesto'] = contexts
+        return (textlist.reset_index(drop=True))
+
+    # %% Ha in input findcontexts, associa i riferimenti bibliografici ad ogni contesto.
+
+    def findbib(self, contexts):
+        infobib = pd.DataFrame()
+        rif_org = pd.DataFrame()
+        for ind, row in contexts.iterrows():
+            queryData = {'queryType': 'bib', 'row': row}
+            bib = self.queryHandler.query(queryData, pandas=True, dbFile='bibliografia/BiblioTLIO.db')
+            infobib = pd.concat([infobib, bib])
+            queryData = {'queryType': 'rif', 'row': row}
+            rif = self.queryHandler.query(queryData, pandas=True)
+            rif_org = pd.concat([rif_org, rif])
+        annoiniz = list(infobib['Anno iniziale'])
+        annofin = list(infobib['Anno finale'])
+        datacod = list(infobib['Data codificata'])
+        datadesc = list(infobib['Data descrittiva'])
+        titoloabb = list(infobib['Titolo Abbreviato'])
+        autore = list(infobib['Autore'])
+        titolo = list(infobib['Titolo'])
+        curatore = list(infobib['Curatore'])
+        areagen = list(infobib['Area generica'])
+        areaspec = list(infobib['Area specifica'])
+        genere = list(infobib['Genere'])
+        forma = list(infobib['Forma'])
+        tipo = list(infobib['Tipo'])
+        iq = list(infobib['IQ'])
+        rif1 = list(rif_org['Rif_organico'])
+        rif2 = list(rif_org['Rif_completo'])
+        contexts['Anno iniziale'] = annoiniz
+        contexts['Anno finale'] = annofin
+        contexts['Data codificata'] = datacod
+        contexts['Data descrittiva'] = datadesc
+        contexts['Autore'] = autore
+        contexts['Titolo Abbreviato'] = titoloabb
+        contexts['Titolo'] = titolo
+        contexts['Curatore'] = curatore
+        contexts['Area generica'] = areagen
+        contexts['Area specifica'] = areaspec
+        contexts['Genere'] = genere
+        contexts['Forma'] = forma
+        contexts['Tipo'] = tipo
+        contexts ['IQ'] = iq
+        contexts['Rif_organico'] = rif1
+        contexts['Rig_completo'] = rif2
+        contexts.pag = contexts.pag.astype(int)
+        chrono = contexts.sort_values(by=['Anno iniziale', 'Rif_organico', 'pag'])   
+        cols = ['links','Titolo Abbreviato', 'Rif_organico', 'tipostanza', 'stanza', 'verso', 'pag', 'riga', 'IQ', 'lemma', 'cat_gr', 'disambiguatore', 'contesto', 'Autore', 'Titolo',  'Anno iniziale', 'Anno finale', 'Data codificata', 'Data descrittiva', 'Area generica', 'Area specifica', 'Genere', 'Forma', 'Tipo', 'Curatore', 'ntx', 'pitxt', 'elemlen', 'mappa', 'numperiod', 'numorg', 'sigla', 'vol', 'col', 'numbrano', 'Rig_completo', 'cod']
+        clean_df = chrono.reindex(columns=cols + list(chrono.columns.difference(cols)))
+        return (clean_df.reset_index(drop=True))
+    
+    #%% funzione stringa/stringhe da evidenziare
+
+    def highlight (self, bibliocontexts):
+        index = 0
+        for col in bibliocontexts.columns:
+            forme = []
+            if col.startswith('cod'):
+                for ind, row in bibliocontexts.iterrows():
+                    queryData = {'queryType': 'highlight', 'row': row, 'col': col}
+                    forma = self.queryHandler.query(queryData, pandas=True)
+                    forme += list(forma['spec'])        
+                if index == 0:
+                    bibliocontexts['highlight'] = forme
+                else:
+                    bibliocontexts['highlight'+str(index)] = forme
+                index += 1
+        return bibliocontexts
+
+    #%% funzione contesti multipli cumulativa
 
+    def contestimultipli (self, tipo_ricerca, ricerca, index = None):
+        textlist = self.findtexts(tipo_ricerca, ricerca, index)
+        contexts = self.findcontexts (textlist)
+        bibliocontexts = self.findbib (contexts)
+        highlights = self.highlight(bibliocontexts)
+        return highlights

+ 45 - 76
flask_be/engine/cooccorrenze.py

@@ -7,17 +7,18 @@ from .basic_queries import basicQueries
 # Executes query sequences to recover contexts with co-occurrences according to user input
 # Returns Pandas dataframes
 class cooccorrenze(basicQueries):
-
+    
     def __init__(self, dataConfig):
-        self.listOcc = dataConfig['listOcc']
         super().__init__(dataConfig)
 
-    #%% funzione ricerca per cooccorrenze. 
+#%% funzione ricerca per cooccorrenze. 
     # Ha in input un array del tipo [forma/lemma_cercati, tipo_ricerca, ricerca_espansa, iniziale_raddoppiata].
     # l'attributo tipo_ricerca definisce il tipo di ricerca in input (0 per forme, 1 per lemmi, 2 per lemmi con opzione "mostra occorrenze non lemmatizzate").
     # Permette di definire l'intervallo di ricerca (in numero di parole), la possibilità di cercare soltanto all'interno dello stesso periodo (0/1) e/o di cercare le occorrenze in modo ordinato (0/1)
+    
     def ricerca_cooccorrenze (self, listaricerche, intervallo, periodo, ordinate):
         listatesti = pd.DataFrame()
+        cod = 1
         if listaricerche[0][1] == 0:
             ricerca = self.sendBasicQuery(listaricerche[0][0], 'forma', listaricerche[0][2], listaricerche[0][3], pandas=True)
             listatesti = self.findtexts(0, ricerca)
@@ -34,7 +35,46 @@ class cooccorrenze(basicQueries):
         for ricerca, tipo, espansa, raddoppiata in listaricerche[1:]:
             if tipo == 0:
                 search = self.sendBasicQuery(ricerca, 'forma', espansa, raddoppiata, pandas=True)
-                textlist = self.findtexts(0, search)
+            elif tipo == 1:
+                search = self.sendBasicQuery(ricerca, 'lemma', espansa, raddoppiata, pandas=True)
+            elif tipo == 2:
+                search = self.sendBasicQuery(ricerca, 'lemma', espansa, raddoppiata, pandas=True)
+     
+            textlist = self.findtexts(tipo, search)
+            df_new = pd.DataFrame(columns=list(listatesti.columns))
+            cod_cols = []
+
+            for index1, row1 in listatesti.iterrows():
+                for index2, row2 in textlist.iterrows():
+                    cond1 = row1['ntx'] == row2['ntx']
+                    cond2 = row1['numperiod'] == row2['numperiod'] if periodo == 1 else True
+                    cond3 = ((row1['mappa'] - row2['mappa']) != 0) and ((row1['mappa'] - row2['mappa']) in range(-intervallo, intervallo)) if ordinate == 0 else ((row2['mappa'] - row1['mappa']) > 0) and ((row2['mappa'] - row1['mappa']) <= intervallo)
+
+                    if cond1 and cond2 and cond3:
+                        row1[f'cod{cod}'] = textlist.loc[index2, 'cod'].iloc[1]
+                        print (type(textlist.loc[index2, 'cod'].iloc[1]))
+                        cod_cols.append(f'cod{cod}')
+                        df_new = pd.concat([df_new, row1.to_frame().T])
+
+            listatesti = df_new
+
+            cod += 1
+
+            if listatesti.empty:
+                return []
+            else:
+                contexts = self.findcontexts(listatesti)
+                bibliocontexts = self.findbib(contexts)
+                clean = bibliocontexts.drop_duplicates(subset="contesto")
+                highlights = self.highlight (clean)
+        return  highlights.to_dict(orient='records') # is this slow? CHECK!
+        #return clean.to_json(orient='records') # possibilità alternativa -- molte opzioni possibili!
+
+'''
+        for ricerca, tipo, espansa, raddoppiata in listaricerche[1:]:
+            if tipo == 0:
+                search = self.sendBasicQuery(ricerca, 'forma', espansa, raddoppiata, pandas=True)
+                textlist = contesti_multipli.findtexts(0, search)
                 print('vediamo un po')
                 print(listatesti)
                 print(textlist)
@@ -122,75 +162,4 @@ class cooccorrenze(basicQueries):
         clean = bibliocontexts.drop_duplicates()
         #return clean
         return clean.to_dict(orient='records') # is this slow? CHECK!
-        #return clean.to_json(orient='records') # possibilità alternativa -- molte opzioni possibili!
-
-    #%% ha in input le funzioni di ricerca, cerca nell'occorrenziario i puntatori ai contesti e altri elementi ad essi associati. 
-    #l'attributo type definisce il tipo di ricerca in input (0 per forme, 1 per lemmi, 2 per lemmi con opzione "mostra occorrenze non lemmatizzate")
-    def findtexts(self, type, df):
-        textlist = pd.DataFrame()
-        codList = list(df["cod"])
-        listOcc = self.listOcc
-
-        queryData = {'queryType': 'texts', 'querySubtype': type, 'codList': codList}
-
-        for table in listOcc:
-            queryData['table'] = table
-            if type==2:
-                subQueryData = {'queryType': 'pfl', 'codList': codList}
-                subdf = self.queryHandler.query(subQueryData, pandas=True)
-                queryData['formCodList'] = list(subdf["forma"])
-
-            extendequeryReponse = self.queryHandler.query(queryData, pandas=True)
-
-            textlist = pd.concat([textlist, extendequeryReponse])
-
-        return textlist
-
-    # %% ha in input findtexts, restituisce i contesti associati agli elementi localizzati.
-    # Il range dei contesti è impostato di default a 30 parole e può essere rimodulato nel passaggio al contesto singolo.
-
-    def findcontexts(self, textlist, parole):
-        listOcc = self.listOcc
-        contexts = []
-        for ind, row in textlist.iterrows():
-            sigla = row["sigla"]
-            queryData = {'queryType': 'contexts', 'ntxlocal': row["ntx"], 'mappalocal': row['mappa'], 'parole': parole}
-            pointerlist = pd.DataFrame()
-            for table in listOcc:
-                queryData['table'] = table
-                queryresponse = self.queryHandler.query(queryData, pandas=True)
-                pointerlist = pd.concat([pointerlist, queryresponse])
-            
-            fileQueryData = {'sigla': sigla, 'minChar': pointerlist["pitxt"].min(), 'maxChar': pointerlist["pitxt"].max()}
-            cont = self.queryHandler.textQuery(fileQueryData)
-            contexts.append(cont)
-        textlist['contesto'] = contexts
-        return (textlist.reset_index())
-
-    # %% Ha in input findcontexts, associa i riferimenti bibliografici ad ogni contesto.
-
-    def findbib(self, contexts):
-        infobib = pd.DataFrame()
-        rif_org = pd.DataFrame()
-        for ind, row in contexts.iterrows():
-            queryData = {'queryType': 'bib', 'row': row}
-            bib = self.queryHandler.query(queryData, pandas=True, dbFile='bibliografia/BiblioTLIO.db')
-            infobib = pd.concat([infobib, bib])
-            queryData = {'queryType': 'rif', 'row': row}
-            rif = self.queryHandler.query(queryData, pandas=True)
-            rif_org = pd.concat([rif_org, rif])
-        anno = list(infobib['Anno iniziale'])
-        titolo = list(infobib['Titolo Abbreviato'])
-        iq = list(infobib['IQ'])
-        rif1 = list(rif_org['Rif_organico'])
-        rif2 = list(rif_org['Rif_completo'])
-        contexts['Anno iniziale'] = anno
-        contexts['Titolo Abbreviato'] = titolo
-        contexts ['IQ'] = iq
-        contexts['Rif_organico'] = rif1
-        contexts['Rig_completo'] = rif2
-        contexts.pag = contexts.pag.astype(int)
-        chrono = contexts.sort_values(by=['Anno iniziale', 'Rif_organico', 'pag'])   
-        cols = ['links','Titolo Abbreviato', 'Rif_organico', 'tipostanza', 'stanza', 'verso', 'pag', 'riga', 'IQ', 'lemma', 'cat_gr', 'disambiguatore', 'contesto']
-        clean_df = chrono[cols].reset_index()
-        return clean_df
+        #return clean.to_json(orient='records') # possibilità alternativa -- molte opzioni possibili!'''

+ 20 - 1
flask_be/engine/parsing_utilities.py

@@ -1,5 +1,7 @@
+import unicodedata
 
 #%% funzione combinazioni <> è chiamata da interpreter
+## DA MODIFICARE PER DB CIFRATO
 def combinations(s):
   result = []
   start = s.find("<")
@@ -12,6 +14,23 @@ def combinations(s):
   return result
 
 #%% funzione interprete, sta alla base di ogni ricerca
+## DA MODIFICARE PER DB CIFRATO
 def interpreter (data):
     clean_data= "'"+data.replace("*", "%").replace("?", "_").replace(" ","").replace("'", "''").replace("’", "''") +"'"
-    return combinations(clean_data)    
+    return combinations(clean_data)    
+
+# %% funzione iniziale raddoppiata, è chiamata dalle funzioni di ricerca con iniziale raddoppiata
+def inizialeraddoppiata (data):
+    doubleddata=[]
+    for el in data:
+        if el[1] != "%" and "_":
+            doubleddata = doubleddata + ["'"+ el[1] + el[1:]]
+    return doubleddata
+
+# %% funzione normalizza stringa (ricerca espansa), è chiamata dalle funzioni di ricerca espansa
+## DA MODIFICARE PER DB CIFRATO
+def normalize(stringa):
+    return unicodedata.normalize('NFKD', stringa).encode('ASCII', 'ignore').decode('utf-8')
+
+def list_normalize(lista):
+    return [normalize(stringa) for stringa in lista]

+ 19 - 7
flask_be/interface_sqlite3/query_handlers.py

@@ -135,15 +135,14 @@ def prepareQueryString(queryData):
         
         strlist = ",".join(str(c) for c in codList)
         if subtype==0:
-            return f"SELECT tab.cod, tab.ntx, tab.pitxt, tab.elemlen, tab.mappa, tab.numperiod, tab.links, tab.numorg, intbib.sigla, tab.vol, tab.pag, tab.riga, tab.col, tab.tipostanza, tab.stanza, tab.verso, lem.spec AS lemma, lem.cat AS cat_gr, lem.omo AS disambiguatore FROM {table} AS tab INNER JOIN intbib ON tab.ntx = intbib.ntx INNER JOIN lem ON tab.indlem = lem.cod WHERE tab.cod IN ({strlist})"
+            return f"SELECT tab.cod, tab.ntx, tab.pitxt, tab.elemlen, tab.mappa, tab.numperiod, tab.links, tab.numorg, intbib.sigla, tab.vol, tab.pag, tab.riga, tab.col, tab.tipostanza, tab.stanza, tab.verso, tab.numbrano, lem.spec AS lemma, lem.cat AS cat_gr, lem.omo AS disambiguatore FROM {table} AS tab INNER JOIN intbib ON tab.ntx = intbib.ntx INNER JOIN lem ON tab.indlem = lem.cod WHERE tab.cod IN ({strlist})"
         elif subtype==1:
-            return f"SELECT tab.cod, tab.ntx, tab.pitxt, tab.elemlen, tab.mappa, tab.numperiod, tab.links, tab.numorg, intbib.sigla, tab.vol, tab.pag, tab.riga, tab.col, tab.tipostanza, tab.stanza, tab.verso, lem.spec AS lemma, lem.cat AS cat_gr, lem.omo AS disambiguatore FROM {table} AS tab INNER JOIN intbib ON tab.ntx = intbib.ntx INNER JOIN lem ON tab.indlem = lem.cod WHERE tab.indlem IN ({strlist})"
+            return f"SELECT tab.cod, tab.ntx, tab.pitxt, tab.elemlen, tab.mappa, tab.numperiod, tab.links, tab.numorg, intbib.sigla, tab.vol, tab.pag, tab.riga, tab.col, tab.tipostanza, tab.stanza, tab.verso, tab.numbrano, lem.spec AS lemma, lem.cat AS cat_gr, lem.omo AS disambiguatore FROM {table} AS tab INNER JOIN intbib ON tab.ntx = intbib.ntx INNER JOIN lem ON tab.indlem = lem.cod WHERE tab.indlem IN ({strlist})"
         elif subtype==2:
             if formCodList is None:
                 return None
             strform = ",".join(str(c) for c in formCodList)
-            return f"SELECT tab.cod, tab.ntx, tab.pitxt, tab.elemlen, tab.mappa, tab.numperiod, tab.links, tab.numorg, intbib.sigla, tab.vol, tab.pag, tab.riga, tab.col, tab.tipostanza, tab.stanza, tab.verso, lem.spec AS lemma, lem.cat AS cat_gr, lem.omo AS disambiguatore FROM {table} AS tab INNER JOIN intbib ON tab.ntx = intbib.ntx INNER JOIN lem ON tab.indlem = lem.cod WHERE tab.indlem IN ({strlist}) OR (tab.indlem = 0 AND tab.cod IN ({strform}))"
-
+            return f"SELECT tab.cod, tab.ntx, tab.pitxt, tab.elemlen, tab.mappa, tab.numperiod, tab.links, tab.numorg, intbib.sigla, tab.vol, tab.pag, tab.riga, tab.col, tab.tipostanza, tab.stanza, tab.verso, tab.numbrano, lem.spec AS lemma, lem.cat AS cat_gr, lem.omo AS disambiguatore FROM {table} AS tab INNER JOIN intbib ON tab.ntx = intbib.ntx INNER JOIN lem ON tab.indlem = lem.cod WHERE tab.indlem IN ({strlist}) OR (tab.indlem = 0 AND tab.cod IN ({strform}))"
     ######################
     elif type=='contexts':
         try:
@@ -154,7 +153,7 @@ def prepareQueryString(queryData):
         except KeyError as err:
             raise KeyError('Missing required data for query type ' + type + ': ' + str(err))
         return f"SELECT tab.pitxt, tab.elemlen FROM {table} AS tab WHERE tab.ntx = {ntxlocal} AND tab.mappa <= {mappalocal+int(parole/2)} AND tab.mappa >= {mappalocal-int(parole/2)}"
-    
+
     #################
     elif type=='bib':
         try:
@@ -162,7 +161,7 @@ def prepareQueryString(queryData):
             sigla = row['sigla']
         except KeyError as err:
             raise KeyError('Missing required data for query type ' + type + ': ' + str(err))
-        return f"SELECT [Anno iniziale], [Titolo Abbreviato], IQ FROM datibib WHERE Sigla='{sigla}'"
+        return f"SELECT [Anno iniziale], [Anno finale], [Data codificata], [Titolo Abbreviato], [Autore], [Titolo], [Curatore], [Data descrittiva], [Area generica], [Area specifica], [Genere], [Forma], [Tipo], IQ FROM datibib WHERE Sigla='{sigla}'"
     
     #################
     elif type=='rif':
@@ -173,10 +172,23 @@ def prepareQueryString(queryData):
         except:
             return None
         return f"SELECT head AS Rif_organico, full AS Rif_completo FROM org WHERE (indice='{numorg}' AND ntx='{ntx}')"
-
+    
+    #################
+    elif type=='highlight':
+        try:
+            row = queryData['row']
+            col = queryData['col']
+        except:
+            return None
+        return f"SELECT spec FROM form WHERE cod={row[col]}"
+    
     #####
     else:
         raise ValueError('Unrecognized query type: ' + type)
+    
+
+
+
 
 
 # Utility for non-Pandas queries

+ 27 - 0
tester_prova.py

@@ -19,3 +19,30 @@ x = requests.post(url, json = testDTO)
 
 print(x.text)
 # %%
+testONEdto = {
+    "queryList": [
+        {
+            "stringa": "cavaliere",
+            "espansa": 0,
+            "raddoppiata": 0,
+            "tipo": "forma"
+        },
+        {
+            "stringa": "corte",
+            "espansa": 0,
+            "raddoppiata": 0,
+            "tipo": "forma"
+        }
+    ],
+    "cooccorrenze": {
+        "distanza": "1",
+        "stesso_periodo": 0,
+        "ordinate": 0
+    }
+}
+
+
+x = requests.post(url, json = testONEdto)
+# %%
+x
+# %%