4.3                   manipolazione della query per I.R.S.  più efficiente

 

La struttura implementata per la realizzazione della ricerca libera per keywords si sarebbe basata dunque sull’elaborazione della stringa originale di query.

Essa sarebbe stata scomposta in tokens, i quali sarebbero stati cercati all’interno dell’ontologia infor, rappresentazione dei contenuti semantici dei documenti contenuti nella bibliografia, e dunque gli idi estratti dai documenti che avessero rispettato le condizioni della prima interrogazione, avrebbero costituito l’espressione della seconda query di select destinata all’interrogazione verso la tabella libri.

Tutti i processi di questa successione di operazioni sarebbero stati cruciali ed essenziali, e l’ottimizzazione anche di uno solo di essi avrebbe costituito un miglioramento di tutta l’operazione di I.R..

La seconda parte del processo di interrogazione per query libera non sarebbe stato direttamente suscettibile di ulteriori miglioramenti, poiché l’estrazione dei documenti dalla bibliografia in modo efficiente sarebbe dipesa dal corretto funzionamento della prima funzione di select, ossia dalla capacità delle procedure implementate nel riuscire a risalire ai giusti campi idi della tabella infor dalle parole della query tokenizzata.

Dunque i miglioramenti al sistema avrebbero dovuto riguardare proprio quest’ultima parte citata, ed essere inserite nella successione delle procedure di interrogazione dopo il processo di tokenizzazione e prima della funzione di select delle parole tokenizzate della query verso l’ontologia infor.

Infatti la parte precedente risultava già ben architettata, e fino al momento in cui la query non venisse tokenizzata e quindi trasferita all’array,[1] non sarebbe stato possibile aggiungervi processi o modificarne le prestazioni.

Sarebbe invece stato possibile applicare tutta una serie di strutture, nell’ordine di quanto esaminato nella sezione dedicata all’I.R., che avessero potuto eseguire delle operazioni di normalizzazione e di stemming sulla query inserita dall’utente.

In realtà un primo e flebile processo di normalizzazione della stringa di query sarebbe già avvenuta durante la sua tokenizzazione, ma vi erano altre operazioni inseribili fra la tokenizzazione e  la costruzione della prima funzione di select.

Un esame distaccato dal contesto in questione della stringa ridotta a tokens avrebbe potuto portare ad una visione astratta della stringa rappresentata all’interno dell’array ad un insieme di elementi,[2]  ed ogni elemento avrebbe costituito un ciclo nel primo processo di select, visto che ognuna di queste parole avrebbe potuto essere una chiave potenziale riconducibile ad un argomento dell’ontologia infor.

Preso atto di quanto affermato, era evidente che la durata della prima interrogazione verso il database sarebbe stata in relazione diretta col numero di parole in essa cercate, [3] e dunque una prima ottimizzazione avrebbe potuto consistere nell’eliminazione di elementi superflui, nello specifico rappresentati da parole inutili e ridondanti quali gli articoli, le preposizioni semplici e composte, ecc…,il cui insieme è detto stopwords.

L’eliminazione delle stopwords, oltre a diminuire i tempi di esecuzione di tutta la prima funzione di select, avrebbe migliorato l’efficienza del funzionamento di tutta la struttura, poiché per le strutture di controllo usate all’interno delle procedure le parole di stop avrebbero costituito elementi che avrebbero portato a fraintendimenti: prendiamo ad esempio le due stringhe x = ’ il deserto occidentale ’ ed y = ‘ deserto occidentale ’.

Ipotizziamo di eseguire due interrogazioni distinte, la prima con la stringa x e la seconda con la stringa y: secondo le strutture implementate fino a questo momento entrambe sarebbero state tokenizzate, e quindi avremmo ottenuto i seguenti array:

 

ArrayX

ArrayY

ArrayX[1]

il

ArrayX[2]

deserto

ArrayX[3]

occidentale

ArrayY[1]

deserto

ArrayY[2]

occidentale

 

Ogni elemento di ciascun array avrebbe poi costituito un’espressione di select verso la tabella infor, e quindi è subito evidente che mentre la funzione di select relativa alla query X avrebbe compiuto un ciclo in più della funzione di select relativa alla query Y peggiorando nella velocità di esecuzione.

Inoltre ipotizzando che l’utente avesse selezionato l’opzione di ricerca almeno una parola, allora i documenti estratti tramite la query X sarebbero stati gli stessi ottenuti con la query Y, ma se invece egli avesse preferito l’opzione tutte le parole, i documenti estratti dalla prima funzione di select non avrebbero potuto essere gli stessi poiché l’articolo determinativo “il” costituiva una chiave da tenere in considerazione per il verificarsi delle condizioni necessarie all’interrogazione verso la tabella infor e dunque verso l’archivio dei documenti.

Se invece vi fossero state una serie di strutture capaci di riconoscere che l’articolo “il” avrebbe potuto essere eliminato, le query avrebbero potuto estrarre, come dovuto, gli stessi documenti.

La struttura da realizzare avrebbe dovuto quindi esaminare che ogni elemento dell’array non fosse stato una stopwords, e nel caso contrario provvedere alla generazione di un nuovo array privo dell’elemento da eliminare.

Ma vi sarebbero stati altri casi di ambiguità costituita semplicemente dal modo nel quale venivano scritti gli stessi concetti, e quindi essendo i concetti espressi gli stessi, se essi fossero stati stringa di una query, anche i documenti che alla fine l’interrogazione avrebbe dovuto estrarre dovevano essere gli stessi.

Riassumendo, prima di analizzare nel dettaglio l’implementazione delle procedure di Tokenizzazione, di Stopwords e di Normalizzazione e Stemming, il sistema di ricerca libera per keywords si sarebbe arricchito di queste due ulteriori strutture, che avrebbero permesso di ridurre i tempi di interrogazione verso il database, ed avrebbero eliminato degli elementi ridondanti, possibili fonti di ambiguità e di fraintendimento di query riconducibili allo stesso significato.

 

4.4                   tokenizzazione

 

Per tokenizzazione si intende quel processo di manipolazione di una stringa attraverso il quale essa viene suddivisa in unità basilari (parole) dette tokens: ogni token è rintracciabile tramite un indice, e può essere  connotato con delle informazioni aggiuntive, come la propria analisi  sintattica e semantica.

Nel caso specifico la tokenizzazione avrebbe dovuto limitarsi ad una manipolazione fisica della stringa, e non sarebbe stato necessario connotare il token di alcuna informazione aggiuntiva, se non di un semplice indice numerico per la sua reperibilità.

La tokenizzazione sarebbe stata eseguita con poche righe di codice grazie alla vasta gamma di funzioni per la manipolazione delle variabili ed, in questo caso, più precisamente, delle stringhe di testo offerte da Php.[4]

Tramite la funzione predefinita explode sarebbe stato possibile, utilizzando un array come variabile d’appoggio, suddividere la stringa, parola per parola, in base ad un carattere separatore: il risultato sarebbe stato un array composto da N elementi dove N corrisponde al numero delle parole contenute nella stringa sottoposta alla funzione di esplode, ed avrebbe sopperito anche all’indicizzazione dei tokens; ciascun elemento dell’array avrebbe contenuto dunque una parola della query.

La tokenizzazione inizialmente presa in considerazione per implementare le opzioni di ricerca libera-tutte le parole e/o ricerca libera-almeno una parola della funzione di ricerca libera, divenne poi necessaria anche per la corretta esecuzione dell’estrazione dei campi idi dalla tabella infor per l’esecuzione di un processo di I.R. che corrispondesse ai criteri proposti dal C.L.I.R., e sempre riguardo alla realizzazione di un sistema di I.R., la tokenizzazione avrebbe costituito la base senza la quale non sarebbe stato possibile sottoporre la query ad alcun processo di normalizzazione e di stemming.[5]

 

4.5                   eliminazione delle stopwords

 

In base a quanto affermato precedentemente sarebbe stato necessario implementare una procedura che intervenisse, dopo la tokenizzazione della query, e testasse per ogni token, se il suo valore corrispondesse a quello di una stopword.

La procedura avrebbe dovuto scorrere quindi tutto l’array contenente la stringa di query precedentemente tokenizzata ed eseguire il controllo relativo alla presenza o meno di stopwords; nel caso in cui esse fossero state trovate, allora avrebbe dovuto sopperire alla loro eliminazione dall’array.

La prima risorsa di cui la procedura di eliminazione delle stopwords avrebbe avuto bisogno sarebbe dunque una lista delle parole di stop in base alla quale eseguire tutte le operazioni successive.

La lista avrebbe dovuto essere composta per ciascuna lingua rappresentata nel sito, dato che la sua redazione monolingue avrebbe compromesso il funzionamento del C.L.I.R. precedentemente implementato.

La struttura del database bibliografiapiste sarebbe stata nuovamente ritoccata, con l’aggiunta di una nuova tabella, stopwords che avrebbe accolto le parole di stop.

La tabella avrebbe contenuto un solo campo, detto parole, all’interno del quale sarebbero state inserite tutte le parole di stop utili e necessarie al funzionamento della struttura.

Così come realizzato per la tabella infor, anche per la tabella stopwords, una volta raggiunto lo spazio massimo supportato per ogni record, sarebbe stato possibile aggiungerne uno nuovo, inserendovi degli aggiornamenti alle lingue già rappresentate, o magari inserendo la rappresentazione di un nuovo linguaggio:[6]

 

Parole

Italiano: di,a,di,da,in,con,su,per,tra,fra,il,lo,la,gli,le,questo,codesto,, ecc…

Inglese: a,of,an,from,on,with,over,up,for,throught,across,,long, between,ecc…

Portoghese: a.bem,e,longe,para,se,você,abaixo,com,ela,mais,por,sem, ecc…

Spagnolo: a,aquí,cuantos,esta,misma,nosotras,querer,tales,usted,acá, ecc…

 

La procedura, dunque avrebbe dovuto estrarre dalla tabella stopwords tutti i records, i cui valori sarebbero stati temporaneamente caricati all’interno di una variabile di appoggio.

La stringa di appoggio sarebbe anch’essa stata sottoposta alla funzione di explode,[7] e quindi tokenizzata, questo semplicemente per avere a disposizione un elenco indicizzato, parola di stop per parola di stop, al quale riferirsi con un semplice ciclo ricorsivo.

Infatti la struttura che avrebbe realizzato il confronto fra i tokens della query e quelli delle parole di stop sarebbe stato implementato con due cicli annidati[8] (dove cioè ogni giro del primo ciclo il secondo avrebbe compiuto tutte le proprie iterazioni) i cui indici sarebbero stati usati per lo scorrimento degli elementi dei due array.

I tokens dell’array contenente la tokenizzazione della stringa di query, se fossero stati identificati con un token di stop, avrebbero assunto come valore la stringa --- ad indicare la cancellazione dell’elemento.

La procedura poi avrebbe ricostruito la query, sempre mantenendola fisicamente tokenizzata, escludendo quegli elementi il cui valore fosse stato cancellato.

 

4.6                   stemming per normalizzazione della query

 

La procedura di normalizzazione avrebbe dovuto realizzare due processi principali:

 

·              avrebbe dovuto attingere ad un archivio contenente suffissi e prefissi da ricercare all’interno dei tokens della query,

 

·              se questi fossero stati presenti avrebbe dovuto procedere alla loro elisione dal valore del token del quale avrebbero costituito o la testa (se prefissi), o la coda (se suffissi o flessioni), o entrambe (una struttura della del tipo: prefisso - tema o radice della parola - suffisso o flessione)

 

Come la struttura implementata per l’eliminazione delle stopwords dalla tokenizzazione della query avrebbe dovuto riferirsi ad una tabella nel database bibliografiapiste contenente l’archivio delle diverse parole di stop, così questa procedura avrebbe dovuto riferirsi ad una ulteriore tabella contenente i prefissi ed i suffissi eventualmente da eliminare dalle parole della query.

La tabella sarebbe stata chiamata normalizzatore, e sarebbe stata organizzata in  campi:

 

·        Suffissi: contenente le flessioni grammaticali, le desinenze da apporre alla radice di una parola

 

·        Prefissi: contenente le strutture da premettere al tema od alla radice della parola.

 

Entrambi i campi avrebbero dovuto comprendere prefissi e suffissi di tutte le lingue rappresentate all’interno del sito, e quindi la tabella normalizzatore avrebbe assunto la seguente architettura:

 

Suffissi :

are,ere,ire,ato,ata,ano,ana,imo,imi,nte,ecc...

Suffissi :

ing, es,s,er,ed,an,/’s,ecc…

Prefissi :

stra, super, iper,ecc…

Prefissi :

over,never,ever,ecc…

 

La struttura, come le tabelle realizzate precedentemente, avrebbe avuto un’elasticità tale da poter essere prima di tutto aggiornata per l’inserimento di nuove stringhe nei campi già realizzati, e poi per l’aggiunta di nuovi suffissi e prefissi di ulteriori lingue.

La struttura della tabella, inoltre, avrebbe consentito uno stemming con risultati corretti sia di stringhe monolingue ( a prescindere da quale fosse stata la lingua di redazione) sia multilingue, mantenendo questa caratteristica già realizzata per la formulazione di query nel rispetto dei principi del C.L.I.R.

La prima parte della procedura di normalizzazione avrebbe dovuto provvedere all’estrazione dei prefissi e dei suffissi contenuti nei campi della tabella normalizzatore.

Questi sarebbero stati salvati temporaneamente in una stringa, poi sottoposta, come visionato per la procedura di stopwords, alla funzione di explode per ottenere una lista indicizzata delle strutture da utilizzare per la normalizzazione dei tokens di query.

La struttura di normalizzazione, allora, avrebbe dovuto procedere al processo di stemming: analizzare ogni token (precedentemente già passato dalla procedura di stopwords), ed identificarvi, se presenti, quei suffissi e quei prefissi aggiunti durante la  corretta flessione grammaticale delle parole e presenti nell’array precedentemente generato dalla tokenizzazione dei contenuti della tabella normalizzatore tramite la funzione di explode.

Anche in questo caso sarebbero occorsi due cicli annidati per riuscire a controllare per ciascun token di query tutti i tokens di normalizzazione.

Una volta identificato il caso in cui la parola avesse contenuto in testa uno di questi prefissi, o in coda uno dei suffissi, il sistema avrebbe dovuto provvedere all’eliminazione delle parti superflue sostituendo all’interno dell’elemento in questione dell’array la parola priva della sua testa e/o coda.[9]

Sarebbe stato inoltre necessario, sempre nell’ordine di voler ricondurre ciascuna parola alla propria radice, controllare se la coda della parola già troncata, finisse per una vocale o per consonante.

Nel primo caso una ulteriore procedura avrebbe provveduto all’eliminazione della vocale, nel secondo caso la stessa avrebbe controllato se la consonante fosse stata una ‘s’, associabile alla flessione inglese e spagnola del plurale, e quindi anch’essa da eliminare.

            A questo punto la query iniziale era stata manipolata profondamente ed al massimo livello possibile (senza chiaramente intaccarne le informazioni trasportate e necessarie all’interrogazione verso il database).

IL sistema di recupero delle informazioni sarebbe inoltre stato capace di eseguire interrogazioni multilinguistiche al database proprio grazie all’architettura delle procedure di normalizzazione ed alla costruzione dell’ontologia Infor, capaci di essere estese in qualsisasi momento al supporto di un nuovo linguaggio.


Sarebbe stato addirittura possibile formulare verso questo C.L.I.R.S. query contemporaneamente composte da parole in più lingue, come ad esempio: “caravan’s tracks del deserto occidentale”.

L’esempio di interrogazione è assolutamente improbabile, ma illustra a dovere le potenzialità del sistema di C.L.I.R., che se implementato al supporto delle lingue in gioco, avrebbe realmente trattato e manipolato l’interrogazione ed il Retrival dei testi pertinenti in modo del tutto indipendente dalla query stessa di partenza.

 



[1] Array che l’avrebbe contenuta parola per parola.

[2] I tokens, cioè le parole.

[3] Chiamando Tarray[n] il tempo impiegato nell’esecuzione della funzione di select dell’elemento N dell’array (token della stringa di query) è evidente che il tempo totale dell’esecuzione di tutta l’interrogazione sarebbe dato dalla sommatoria di tutti i Tarray[n] dove n = numero di parole della stringa di query, e dunque:

Ttotale = å ( i ³ 1 ) ( i £ N ) Tarray[i]

[4] La struttura necessaria alla tokenizzazione della stinga di query sarebbe stata costituita dalla funzione explode. La funzione explode  suddivide una stringa utilizzando un determinato carattere di separazione come criterio del troncamento delle parola della stringa, ed essa inserisce i valori ricavati in un array: la sua sintassi corretta sarebbe stata:

$array = ‘explode (“carattere separatore”, “stringa”)’; dove, ipotizzando che la stringa da tokenizzare, contenuta nella variabile $query, fosse stata: “le piste carovaniere del deserto occidentale” la sintassi della funzione sarebbe stata:

$array = ‘explode (“ ”, “$query”)’; ed avrebbe prodotto:

$array[1] =’,

$array[2] =’pistè,

$array[3] =’carovanierè,

$array[4] =’del’,

$array[5] =’deserto’,

$array[6] =’occidentalè

[5] L’implementazione delle procedure di normalizzazione e stemming sarà descritta successivamente, ma per entrambe i concetti è opportuno riferirsi alla 2° parte dedicata all’I.R..

[6] La lista di Stopword nelle varie lingue è tratta da Oracle Text Reference Release 9.0.1, reperibili presso il seguente URL: http://download-east.oracle.com/otndoc/oracle9i/901_doc/text.901/a90121/astopsup.htm

[7] In questo caso la funzione di explode non avrebbe avuto indicato, nella sua sintassi, il carattere separatore come blank (spazio vuoto, rappresentato da “ “), ma il carattere che divideva una stopword dalla successiva sarebbe stato “ , “, e dunque il codice corretto:

$arrayS = explode(",", $stopwords)

dove la variabile $stopwords avrebbe contenuto il valore dei campi parole della tabella stopwords,

l’array $arrayS avrebbe contenuto la tokenizzazione di $stopwords e, come precedentemente accennato, il carattere separatore per la creazione degli elementi dell’array sarebbe stato “,”.

[8] I due cicli annidati avrebbero permesso di testare, per ogni token della query, tutti i tokens di stopwords.

Date le variabili i e j rispettivamente indice del primo e del secondo ciclo,

le variabili N e M rispettivamente il numero di parole della query ed il numero di tokens di stop,

arrayQ ed arrayS rispettivamente gli array contenenti i tokens della Query e le parole di Stop la sintassi sarebbe stata:

for ($i = 0; $i < $N; $i = ++$i) {

                for ($j = 0; $j < $M; $j = ++$j) {

                               IF (strtolower($arrayQ[$i]) == $ arrayS [$j]) {

                               $arrayQ[$i] = "---"; } // end IF

}              // end 2° for

} // end 1°for

La procedura eseguendo il codice citato avrebbe controllato, come da progetto, per ogni tokens di query se il suo valore fosse stato contenuto fra quelli estratti dalla tabella stopwords.

Se il test lo avesse verificato allora l’elemento dell’array corrispondente al tokens di stop avrebbe assunto il valore ‘---‘, ossia la procedura avrebbe letteralmente cancellato il valore dell’elemento arrayQ[$i].

La funzione strlower è una funzione di manipolazione delle stringhe predefinita di Php, e consente di riportare tutti i caratteri maiuscoli incontrati all’interno di una stringa ai corrispettivi minuscoli.

Anche in questo caso, così come per quanto espresso riguardo alle chiavi della tabella infor, sarebbe stato possibile applicare la procedura di stemming con lo stesso risultato di normalizzazione a query monolingue o multilingue.

[9] Infatti avrebbe potuto verificarsi il caso in cui la parola contenuta nel token avesse presentato sia un prefisso sia un suffisso normalizzabile.

Definendo con P  la lunghezza del prefisso da eliminare, con  L la lunghezza della parola e con S la lunghezza del suffisso da eliminare: Il troncamento della stringa in coda sarebbe avvenuta dal carattere di posizione L – Z, mentre  l’elisione in testa avrebbe dovuto verificarsi dal carattere sino al carattere P.

Quindi della parola da normalizzare avrebbero dovuto essere considerati i caratteri da N a (Z – P).