Important Announcement
PubHTML5 Scheduled Server Maintenance on (GMT) Sunday, June 26th, 2:00 am - 8:00 am.
PubHTML5 site will be inoperative during the times indicated!

Home Explore Tesi

Tesi

Published by bernardinello, 2018-11-22 06:07:49

Description: Tesi

Search

Read the Text Version

UNIVERSITÀ DEGLI STUDI DI PADOVACORSO DI LAUREA IN INGEGNERIA INFORMATICA Dipartimento di Ingegneria dell’Informazione Un motore di raccomandazione per il supporto clientiLaureando: Relatore:Nicola Elia PIGATO Prof. Carlo FANTOZZI 26 Novembre 2018ANNO ACCADEMICO 2017-2018



iii«A human is not a device that reliably reports a gold standard judgment of relevance of adocument to a query. Rather, humans and their relevance judgments are quite idiosyncraticand variable. But this is not a problem to be solved: in the final analysis, the success ofan Information Retrieval system depends on how good it is at satisfying the needs of theseidiosyncratic humans.» Hinrich Schütze



v UNIVERSITÀ DEGLI STUDI DI PADOVA Sommario Scuola di Ingegneria Dipartimento di Ingegneria dell’Informazione Corso di Laurea in Ingegneria Informatica Un motore di raccomandazione per il supporto clienti di Nicola Elia PIGATOQuesta relazione illustra il progetto realizzato durante un tirocinio che ha portato al-la realizzazione di un sistema web che permetta di ottenere una lista di testi correlatia uno dato, sviluppato per un servizio di customer care. Viene introdotta l’azienda in cui è stato svolto il tirocinio e il problema che ha re-so necessaria la realizzazione di questo progetto. Vengono poi illustrate le tecnichematematiche più comuni alla base dell’information retrieval, in modo da poter darea questa trattazione una base teorica, oltre che pratica. L’analisi dei requisiti che ilprogetto deve realizzare fa da preambolo all’elenco degli strumenti utilizzati duran-te il tirocinio, per poi proseguire nella descrizione delle soluzioni ideate. Infine èriportata la soluzione scelta da consegnare al cliente, con la relativa implementazio-ne e snippet di codice rilevanti. Una breve riflessione sui possibili sviluppi futuri delprogetto realizzato conclude l’elaborato.



viiIndice1 Introduzione 1 1.1 L’azienda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 Il problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 Stato dell’arte 3 2.1 TF-IDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2.1.1 TF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.1.2 IDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.1.3 TF-IDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2.2 Vector space model e cosine similarity . . . . . . . . . . . . . . . . . . . 6 2.3 Ottimizzazioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 Analisi dei requisiti 93.1 Requisiti funzionali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93.2 Requisiti non funzionali . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 Strumenti utilizzati 114.1 Apache server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114.2 PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114.3 JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114.4 JSON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124.5 MySql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134.6 Visual Studio Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144.7 Sugar CRM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144.8 Smarty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154.9 Apache Solr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 Progettazione 215.1 Soluzione in PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215.2 Soluzione in PHP+Solr . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 Implementazione 256.1 Back-end . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256.1.1 Solr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256.1.2 PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286.2 Front-end . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336.2.1 JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336.2.2 DetailView . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346.2.3 EditView . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366.3 Prototipo della soluzione non realizzata . . . . . . . . . . . . . . . . . . 377 Conclusioni 39

viiiA Codice sorgente 41 A.1 caricaSolr.php . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 A.2 getMlt.php . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 A.2.1 Prima parte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 A.2.2 Seconda parte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 A.2.3 Richiesta MLT a Solr . . . . . . . . . . . . . . . . . . . . . . . . . 45 A.2.4 Invio risposta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 A.3 Soluzione non realizzata . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 A.4 Pannello di impostazioni in JavaScript . . . . . . . . . . . . . . . . . . . 50 A.5 DetailView con Smarty . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51Ringraziamenti 55

11 IntroduzioneLa presente relazione illustra il percorso di un’esperienza di tirocinio di 250 ore fina-lizzato alla realizzazione un sistema che possa analizzare una richiesta di assistenzapervenuta ad un centro supporto clienti e suggerire richieste simili già risolte, conl’obiettivo di velocizzare il processo di risoluzione delle richieste dei clienti.1.1 L’aziendaIl tirocinio si è svolto presso Mediamind s.r.l., una società di sviluppo software econsulenza informatica specializzata nel fornire servizi basati su prodotti e tecno-logie open-source. La società si rivolge ad aziende, pubbliche amministrazioni edorganizzazioni che hanno la necessità di utilizzare soluzioni software con lo scopodi migliorare i processi e le performance aziendali ad un costo contenuto. Ciò è resopossibile da un costante impegno nell’adozione di software open-source, che la ren-dono competitiva sul mercato e svincolata da piattaforme proprietarie.L’azienda, fondata da Fabrizio Ferrari nel 2001, è attiva a Rovigo e nonostante ledimensioni contenute (conta meno di 10 dipendenti) vanta clienti importanti qualiInfocert, Aruba, Associazione Bancaria Italiana e Unicredit. Sono proprio le dimen-sioni ridotte a favorire la diffusione della conoscenza aziendale dagli sviluppatoriesperti a quelli con meno esperienza, favorendo un processo di apprendimento ecrescita professionale. Il progetto si andrà ad integrare ad un sistema software sviluppato da Media-mind per conto di InfoCert. InfoCert è una realtà italiana presente nel mercato deiservizi di digitalizzazione e dematerializzazione, nonché una delle principali Certifi-cation Authority a livello europeo per i servizi di Posta Elettronica Certificata, FirmaDigitale e Conservazione digitale dei documenti. Dal 2015 è anche gestore accredi-tato AgID dell’identità digitale di cittadini e imprese. I prodotti offerti da InfoCertai suoi clienti spaziano dalla Posta Elettronica Certificata (PEC), firma e conserva-zione digitale di documenti, fatturazione elettronica e Sistema Pubblico di IdentitàDigitale (SPID).

2 Capitolo 1. Introduzione1.2 Il problemaInfoCert fornisce ai suoi clienti un’attività di assistenza clienti. In particolare è attivauna procedura di invio di richieste di assistenza, che prendono il nome di ’ticket’, chevengono risolte da uno o più team composti da tecnici specializzati nei vari servizie prodotti offerti.L’apertura di un ticket può avvenire: • tramite un apposito form online, in cui un cliente specifica l’ambito e la relativa richiesta; • tramite call-center, nel qual caso un operatore apre il ticket in seguito a una conversazione telefonica con il cliente; • tramite una chat testuale con un operatore, che apre il ticket sulla base delle richieste del cliente; • tramite email, caso in cui uno script controlla periodicamente l’esistenza di nuove email su caselle di posta dedicate (differenziate in base alla categoria di richiesta di assistenza) e crea il ticket corrispondente.Data la costante crescita dei ticket risolti, negli anni si è venuta a formare una quan-tità consistente di tali ticket che possono essere sfruttati per ottenere soluzioni a pro-blemi ricorrenti dei clienti. La ricerca manuale tramite parole chiave, però, non èefficiente in quanto la scelta di un criterio di ricerca piuttosto che un altro può cam-biare i risultati ottenuti, e risulta quindi dispendiosa in termini di tempo. Infocertha quindi ritenuto necessario un sistema di suggerimenti per i suoi operatori chericerchi ticket risolti simili a uno dato, favorendo eventualmente i ticket provenientidallo stesso cliente o inerenti la stessa area tematica.

32 Stato dell’arteIl problema affrontato durante il tirocinio consiste nel confrontare una serie di tickete stabilire quali siano più pertinenti (i.e., più simili) ad uno dato in input. Questaricerca dovrà favorire ticket che presentino le stesse parole più rilevanti, lo stessocliente richiedente, la stessa area di appartenenza e una data di creazione più recen-te.Mentre verificare che due ticket provengano dallo stesso cliente ed appartenganoalla stessa area tematica è immediato e binario, per il confronto del testo è neces-sario costruire un punteggio di somiglianza, in modo tale che testi semanticamentesimili a uno dato presentino punteggi alti, mentre testi che trattano argomenti diver-si assumano punteggi bassi. Su questa parte si concentrerà la parte più consistentedell’analisi del problema.Appare subito evidente che un approccio basato sulla quantità di parole in comunetra due testi non è la scelta ottimale. La lingua italiana, come tutte le lingue, presen-ta molte stopword: parole estremamente comuni sia nella lingua parlata che scritta(come ad esempio articoli, congiunzioni, preposizioni, ma anche saluti o forme dicortesia). Ciò comporta che, presi due testi, le parole in comune più ricorrenti saran-no quasi sempre stopword.Risulta quindi necessario costruire un criterio più elaborato, che riesca a tener con-to delle parole poco rilevanti e quindi ignorarle, e dia maggior rilevanza a paroleparticolarmente caratteristiche di ogni documento (o ticket): questo criterio trovala sua realizzazione nella funzione di peso TF-IDF. In questo capitolo verrà breve-mente riassunto lo stato dell’arte per quanto riguarda i metodi di term weighting piùsemplici nell’information retrieval.2.1 TF-IDFIn information retrieval, la term frequency–inverse document frequency (TF-IDF) è unastatistica numerica che riflette quanto è importante ogni singola parola per un docu-mento contenuto in un insieme di documenti. Il valore di TF-IDF dipende in mododirettamente proporzionale al numero di volte che una parola appare in un docu-mento e in modo inversamente proporzionale al numero di documenti che conten-gono quella parola, considerando che, in generale, alcune parole appaiono più fre-quentemente di altre.TF-IDF è uno degli schemi di term weighting più popolari al giorno d’oggi: si stimache il 70% dei sistemi di suggerimento basati sul testo nelle librerie digitali usi lametrica TF-IDF. [1]TF-IDF combina tra di loro due diversi punteggi: la term frequency (TF) e l’inversedocument frequency (IDF).

4 Capitolo 2. Stato dell’arte2.1.1 TFLa prima forma di term weighting è stata introdotta nel 1957 da Hans Peter Luhn cherifletté sul fatto che ”c’è anche una probabilità che più frequentemente una nozionee una combinazione di nozioni occorrono [in un testo, nda], più importanza dà adesse l’autore per riflettere l’essenza della sua idea generale”. [2] Questo concetto si èpoi evoluto in una funzione di peso chiamata term frequency (TF).L’idea alla base del punteggio di term frequency è banale: un documento che citaspesso un termine ha molto a che fare con quel termine, perciò quel termine dovràricevere un punteggio più alto in quel documento. In questa prospettiva assegniamoad ogni termine in un documento un peso che dipende dal numero di occorrenzedi quel termine nel documento: l’approccio più semplice consiste nell’assegnare ilnumero di occorrenze del termine t nel documento d. [3]Per evitare di favorire documenti lunghi, una variante di questo punteggio chiamata”TF normalizzato” consiste nel dividere il numero di occorrenze del termine per ilnumero totale di parole contenute nel testo in questione.Il punteggio TF (normalizzato) di un termine t in un documento d è dato da: TFt,d = nt,d (2.1) ∑ nt ,d t ∈ddove nx,d rappresenta il numero di occorrenze del generico termine x nel documentod.2.1.2 IDFLa term frequency (TF) appena descritta soffre però di un problema: tutti i terminisono considerati ugualmente importanti ai fini dell’assegnazione del punteggio dirilevanza. Alcuni termini in un documento hanno una bassa (o nessuna) incidenzanel determinare la somiglianza di un documento a uno dato. Per esempio, se stia-mo lavorando con una bibliografia di articoli sul mondo automobilistico troveremoi termini ”motore”, ”velocità” o ”prestazioni” in quasi tutti i documenti, rendendoquesti termini sostanzialmente inutili ai fini della determinazione della similitudine.Per ovviare a questo problema nel 1972 Karen Spärck Jones concepì una interpre-tazione statistica della specificità di un termine, chiamata inverse document frequency(IDF), scrivendo che ”la specificità di un termine può essere quantificata come lafunzione inversa del numero dei documenti in cui occorre.” [4] e diventando l’in-ventrice del punteggio TF-IDF. Citando la prof.ssa Raffaella Bernardi dell’Universitàdi Trento, il punteggio IDF ”stima la rarità di un termine all’interno di tutta la col-lezione di documenti. (Se un termine occorre in tutti i documenti, il suo IDF è paria zero)”[5]. Il punteggio IDF trova utilità anche per penalizzare molte stopword, inquanto contenute in quasi tutti i documenti di una collezione. In altre parole, IDF èuna misura di quanta informazione fornisce una singola parola ed è definito come illogaritmo del quoziente tra il numero di tutti i documenti diviso per il numero di do-cumenti che contengono quella parola. Il punteggio IDF per un termine t all’internodi una collezione di documenti D è quindi: I D Ft,D = log |{d ∈ |D| ∈ d}| (2.2) D:tPer considerare il caso limite in cui il termine t non è contenuto nel corpus di docu-menti (cioè che |{d ∈ D : t ∈ d}| = 0) è prassi comune sommare 1 al denominatore

2.1. TF-IDF 5della frazione (onde evitare una divisione per zero) oppure assegnare direttamentead IDFt,D il valore 0.2.1.3 TF-IDFIl punteggio TF-IDF non è altro che il prodotto tra 2.1 e 2.2: TF-IDFt,d,D = TFt,d · IDFt,D (2.3)A titolo di esempio, calcoliamo il punteggio TF-IDF per alcuni termini delle seguenticitazioni:1. Bisogna avere il caos dentro di sé per partorire una stella danzante. (Nietzsche)2. L’ordine è qualcosa di artificioso; il naturale è il caos.1 (Arthur Schnitzler)3. Se si guarda troppo fisso una stella, si perde di vista il firmamento. (E. A. Poe)Le citazioni contengono, rispettivamente, 12, 11 e 13 termini. I punteggi TF per itermini ”caos”, ”stella”, ”il” e ”ordine” per ognuno dei tre documenti sono: ”caos” ”stella” ”il” ”ordine” 1 1/12 = 0.083 1/12 = 0.083 1/12 = 0.083 0 2 1/11 = 0.091 0 2/11 = 0.182 1/11 = 0.091 30 1/13 = 0.077 1/13 = 0.077 0Appare subito evidente la principale limitazione del punteggio TF: per la secondafrase, parrebbe che ”il” sia un termine più importante di ”caos” per caratterizzare lacitazione, solo perché appare più volte.Mentre, dato N = 3 il numero di documenti (in questo caso, citazioni), i punteggiIDF dei tre termini in esame sono: ”caos” ”stella” ”il” ”ordine”D log 3/2 = 0.405 log 3/2 = 0.405 log 3/3 = 0 log 3/1 = 1.099Calcoliamo infine il punteggio TF-IDF complessivo:”caos” ”stella” ”il” ”ordine”1 0.083 ∗ 0.405 = 0.0336 0.083 ∗ 0.405 = 0.0336 0.083 ∗ 0 = 0 0 ∗ 1.099 = 02 0.091 ∗ 0.405 = 0.037 0 ∗ 0.405 = 0 0.083 ∗ 0 = 0 0.091 ∗ 1.099 = 0.1003 0 ∗ 0.405 = 0 0.077 ∗ 0.405 = 0.031 0.083 ∗ 0 = 0 0 ∗ 1.099 = 0 Possiamo notare come termini unici all’interno di un singolo documento otten-gano un TF-IDF alto (si veda il termine ”ordine” per la seconda frase) mentre terminiin comune tra più frasi mantengano un punteggio basso perché poco caratterizzantiper ognuno di quelli (la parola ”stella” si riferisce a due citazioni) e infine terminimolto comuni e contenuti in tutte le frasi non hanno rilevanza (come l’articolo ”il”,contenuto in tutte e tre le citazioni esaminate).Verrà ora illustrato come vengono combinati e utilizzati i diversi punteggi per ognidocumento. 1Qui ”L’ordine” viene considerato come due parole distinte: ”il” e ”ordine”.

6 Capitolo 2. Stato dell’arte2.2 Vector space model e cosine similaritySe consideriamo l’insieme di tutte le parole contenute nella collezione di testi possia-mo costruire, per ogni documento, un vettore in cui riportiamo ordinatamente tuttii punteggi TF-IDF di ogni parola: così facendo abbiamo creato uno spazio vettorialea T dimensioni, con T uguale al numero totale di termini nell’insieme di documenti,in cui ogni dimensione corrisponde a un termine diverso.Un documento d avrà quindi un vettore dato da: vd = (w1, w2, w3, . . . , wt, . . . , wT)dove wt = TF-IDFi,d,D se il termine t è contenuto in d. 0 Altrimenti.In particolare, wt rappresenta il peso che ha un qualsiasi termine t nel documentod. Questa rappresentazione, proposta per la prima volta nel 1975 da Salton, Wonge Yang [6], è chiamata vector space model e fa parte delle rappresentazioni di tipobag of words: un insieme di parole (e quindi di punteggi) che perdono il loro ordineall’interno del testo e tutte le relazioni grammaticali. Presi due vettori qualsiasi appartenenti a questo spazio vettoriale, è sempre pos-sibile calcolare l’angolo compreso tra essi. Questo torna utile perché, essendo lecoordinate di un vettore rappresentazione numerica della rilevanza di ogni paro-la all’interno del documento rappresentato dal vettore, documenti semanticamentesimili avranno, per ogni parola, punteggi simili e quindi saranno rappresentati davettori con coordinate simili. Se prendiamo due vettori uguali v1 e v2, l’angolo com-preso tra essi è sempre zero qualsiasi sia la dimensione dei due vettori. Possiamoquindi considerare l’angolo compreso tra due vettori come un metro di somiglianzatra i due vettori e quindi tra i due relativi documenti.Per fare ciò usiamo la cosine similarity, o coseno di similitudine, che misura il cose-no dell’angolo compreso tra due vettori: l’angolo compreso tra vettori simili avràquindi un coseno con valori prossimi ad uno, mentre vettori con orientazioni moltodiverse disegneranno un angolo con valori prossimi a zero. È comunque necessariosottolineare che la similitudine di coseno rappresenta un giudizio di orientamento enon di magnitudine: due vettori orientati nella stessa direzione avranno un cosenouguale a 1, se ortogonali avranno un coseno uguale a zero, se opposti2 avranno uncoseno uguale a -1, indipendentemente dalla lunghezza dei vettori.Il coseno di similitudine è infine rappresentato da: similarity = cos θ = A·B = T (2.4) A·B ∑ waiwbi i=1 TT ∑ ∑w2ai w2bi i=1 i=1Questo è il punteggio generalmente utilizzato dai sistemi di information retrievalper confrontare tra di loro due testi e stabilire quanto essi siano simili. 2Dato che il punteggio TF-IDF è sempre maggiore di zero non troveremo mai vettori opposti (ciòpresupporrebbe coordinate negative).

2.3. Ottimizzazioni 72.3 OttimizzazioniSono possibili varie operazioni di ottimizzazione del testo da immettere in un siste-ma di information retrieval. Tra queste ricordiamo l’eliminazione delle stopword daltesto, in quanto come già accennato sono di scarsa importanza per identificare un te-sto in una collezione. Inoltre è possibile sostituire molte parole con i loro sinonimi e,specialmente nelle lingue latine, tutte le coniugazioni di un verbo con il verbo stes-so: questo perché ogni verbo può essere coniugato in decine di modi, e quindi condecine di parole diverse che durante l’analisi sono totalmente scorrelate tra loro. Setrattiamo tutte le coniugazioni come il singolo verbo otterremo una quantità minoredi parole da indicizzare e contemporaneamente un miglioramento dell’accuratezzadel punteggio di similitudine. Infine in caso di concetti formati da due o più parole(come ad esempio ”carta di credito” o ”corso di laurea”) è possibile raggrupparle inun’unica ”parola” in modo da ottenere una precisione ancora maggiore (si pensi alladifferenza tra due documenti che parlano rispettivamente di una ”banca” e di una”banca dati”).



93 Analisi dei requisitiIn questa sezione verranno illustrate le funzionalità minime (requisiti funzionali) cheil progetto dovrà implementare per potersi dire completato. Considerando che il progetto da realizzare non verrà creato ex-novo, bensì andràad integrarsi ad una applicazione web già esistente, dovrà necessariamente sotto-stare a delle specifiche tecniche (requisiti non funzionali) in modo da poter esserecompatibile con le tecnologie adottate e con la struttura utilizzata.3.1 Requisiti funzionaliLe funzionalità che il sistema deve offrire all’utente che lo utilizzerà sono state iden-tificate nelle seguenti: 1. Creare una knowledge base aziendale che contenga tutti i ticket ritenuti im- portanti o interessanti per consultazioni future. 2. Mentre l’utente sta visualizzando un ticket, dovrà poter visualizzare un breve elenco di ticket (non più di 10) che sono in qualche modo correlati a quello visualizzato. 3. Un ticket si può dire correlato ad un altro se: • i testi della richiesta di assistenza sono simili • il testo della soluzione del ticket risolto è simile al testo della richiesta del ticket visualizzato • entrambi i ticket provengono dallo stesso cliente • entrambi i ticket appartengono alla stessa area tematica 4. L’utente può scegliere se utilizzare o meno i parametri del punto precedente. 5. L’utente può scegliere se favorire o meno i ticket più recenti a discapito dei più datati.

10 Capitolo 3. Analisi dei requisiti3.2 Requisiti non funzionaliI requisiti di implementazione, cioè le caratteristiche tecniche che la soluzione dovràrispettare, sono i seguenti: 1. Il progetto dovrà essere realizzato utilizzando PHP e JavaScript ed eventual- mente framework e librerie basati su di essi, in quanto dovrà integrarsi a una applicazione web utilizzante questi linguaggi. 2. Il sistema di suggerimento deve poter gestire una quantità di ticket dell’ordine delle decine di migliaia, mantenendo comunque una velocità apprezzabile. 3. Sebbene sia preferibile una soluzione il più possibile leggera, è consentita l’ag- giunta di ulteriori piattaforme (quali server web, database aggiuntivi o proces- si in background). 4. Considerando che stiamo trattando informazioni non di prioritaria importan- za nella visualizzazione di un ticket, è preferibile che l’elaborazione dei ticket simili sia eseguita in modo asincrono rispetto al caricamento della pagina, in modo tale da non rallentarlo. 5. È preferibile salvare in una cache i risultati, in modo tale da diminuire i tempi di risposta e alleggerire il carico di lavoro nel server.Inoltre il progetto dovrà completarsi entro le 250 ore di tirocinio previste.

114 Strumenti utilizzatiIn questa sezione verranno esposti gli strumenti che sono stati utilizzati per soddi-sfare i requisiti del progetto: saranno accennati i più famosi, quali PHP o JavaScript,mentre verrà dedicata più attenzione a quelli meno conosciuti.4.1 Apache serverPer poter rendere accessibile in rete una qualsiasi applicazione web è necessario uti-lizzare un software che funga da server. Per gli applicativi sviluppati da Mediamindla scelta è ricaduta su Apache HTTP Server [7], un server web libero lanciato nel 1995e sviluppato dalla Apache Software Foundation, disponibile per Linux e Windows,anche se è estremamente più utilizzato in combinazione con il primo.4.2 PHPL’applicazione web a cui si è integrato il progetto di tirocinio è scritta in PHP, comela maggior parte dei siti web presenti in internet attualmente. PHP [8] (acronimoricorsivo di ”PHP: Hypertext Preprocessor”) è un linguaggio di programmazioneinterpretato lato server progettato per lo sviluppo web, anche se viene usato comelinguaggio general purpose. Il codice PHP può essere incorporato in codice HTML,o può essere usato in combinazione con vari template web, CMS (come WordPresso Drumal) e framework, e viene processato da un interprete PHP, generalmente unprogramma che risiede nel server web che combina i risultati del codice PHP inter-pretato ed eseguito (che possono essere qualsiasi tipo di dati, incluse immagini) conla pagina web generata.L’interprete PHP standard è software libero, rilasciato sotto la licenza PHP, che nepermette l’utilizzo senza alcun tipo di costo. Questo, unito a tutti i miglioramentiche ha ricevuto da quando è apparso la prima volta nel 1995, ha portato il PHP adessere il linguaggio di programmazione web più popolare al mondo, utilizzato daquasi l’80% dei siti web [9].4.3 JavaScriptPer le elaborazioni lato client è stato utilizzato JavaScript [10], spesso abbreviato inJS, un linguaggio di programmazione interpretato orientato agli oggetti e agli eventi,ampiamente usato nella programmazione web per creare pagine con effetti dinamiciinterattivi. Inizialmente implementato solo nei browser (quindi lato client), JS è orautilizzato in molte altre tipologie di software quali web server, database e anche inprogrammi non-web, come editor di documenti, visualizzatori PDF e in ambientiruntime. In particolare, per realizzare una comunicazione asincrona tra il web browser eil server si utilizza una tecnica chiamata AJAX (Asynchronous JavaScript and XML)

12 Capitolo 4. Strumenti utilizzatiche permette di effettuare la richiesta di una risorsa (nel nostro caso, una lista di tic-ket) ad un server web in modo indipendente dal browser. Nella richiesta è possibileinviare dati contenuti in variabili di tipo GET o di tipo POST in maniera analoga aquello che succede durante il submit di un form HTML.Il vantaggio di una richiesta asincrona sta proprio nel fatto che i dati sono richiesti alserver e ricevuti in background senza interferire con il comportamento della paginaesistente e senza attendere che l’operazione sia terminata per poter avviarne altre,come invece succede nel caso di una richiesta al server tradizionale. È necessariocomunque precisare che, nonostante il nome, non è obbligatorio usare JavaScript eXML per eseguire richieste AJAX, infatti viene spesso usato il JSON (JavaScript Ob-ject Notation) come formato di interscambio dati.Per effettuare una richiesta AJAX, JavaScript mette a disposizione un oggetto chia-mato XMLHttpRequest che implementa tutte le procedure per realizzarla. Un esem-pio di utilizzo è il seguente: File script.js - script lato clientvar xhr = new XMLHttpRequest();xhr.open('GET', 'paginaPHP.php');xhr.onreadystatechange = function () { var DONE = 4; /* readyState=4 significa che la richiesta è stata eseguita */ var OK = 200; // status=200 è una risposta con successo if (xhr.readyState === DONE && xhr.status === OK) { console.log(xhr.responseText); // Risposta ritornata dalla pagina PHP } else { console.log('Errore: ' + xhr.status); // Descrizione dell'errore }};xhr.send(); // invia la richiesta a paginaPHP.php File paginaPHP.php - script lato server<?phpheader('Content-Type: text/plain'); //imposta il content typeecho \"Hello, World!\"; // Risponde alla richiesta?>In questo esempio la richiesta AJAX è stata eseguita al caricamento della pagina,ma è possibile (e molto comune) eseguirla al verificarsi di certi eventi nella pagina,come ad esempio il click su un bottone, l’inserimento di testo o il posizionamentodel puntatore del mouse in una certa area.4.4 JSONPer scambiare dati tra varie applicazioni web di varia natura e con linguaggi diffe-renti è necessario utilizzare un formato comune a tutte per poter rappresentare datie oggetti in modo standardizzato. Per fare ciò è ampiamente utilizzato il JSON [11](JavaScript Object Notation), uno standard aperto che definisce un formato di file

4.5. MySql 13che utilizza testo umanamente leggibile per l’interscambio di dati e oggetti. Nono-stante il nome, JSON è linguaggio-indipendente anche se usa convenzioni familiariai linguaggi della famiglia C (C, C++, C#, Java, JavaScript, Perl e Python).L’interoperabilità del JSON lo ha reso un formato estremamente utilizzato per le co-municazioni AJAX browser-server, spesso in sostituzione dell’XML grazie alla mag-gior semplicità di manipolazione ed accesso ai dati.Ogni oggetto, inteso come collezione non ordinata di coppie chiave-valore, è rappre-sentato in JSON racchiuso tra parentesi graffe contenenti l’elenco di tutte le coppiechiave-valore, separate da una virgola. Ogni chiave è seguita da due punti che laseparano dal rispettivo valore. In aggiunta agli oggetti si possono rappresentare an-che liste (array) ordinate di valori di qualsiasi tipo tra stringhe, numerici, oggetti,booleani o null. Gli array vengono rappresentati racchiusi tra parentesi quadre.L’esempio che segue mostra un possibile JSON rappresentante un libro: { \"title\" : \"La chiave segreta per l'universo\", \"authors\" : [ \"Lucy Hawking\", \"Stephen Hawking\" ], \"isbn\" : \"978-8804591894\", \"pages\" : 221, \"formats\" : [ { \"type\" : \"Kindle\", \"price\" : 5.00 }, { \"type\" : \"book\", \"price\" : 8.50 } ] }Le funzioni che permettono di codificare (e decodificare) un oggetto in JSON sonorispettivamentejson_encode($obj) e json_decode($str) per PHP eJSON.stringify(obj) e JSON.parse(str) per JavaScript.4.5 MySqlTutte le informazioni contenute in un sito web e le relative relazioni che intercorronotra esse devono essere salvate in un database, per permetterne un’efficiente gestione,indicizzazione, ricerca e recupero.Per InfoCert (e per la maggior parte dei clienti di Mediamind) si è scelto di utilizzarecome database MySql [12], un RDBMS (relational database management system)open-source distribuito e supportato da Oracle Corporation.MySql, distribuito liberamente dal 1995, è ad oggi uno dei database più usati perle applicazioni web, garantendo alte performance anche in caso di intenso trafficodati e un’ottima scalabilità, è stato adottato da piccole e grandi organizzazioni come

14 Capitolo 4. Strumenti utilizzatiGitHub, Tesla, YouTube, Netflix, Booking, Spotify, PayPal, Twitter e Facebook1 edè parte integrante della maggior parte dei CMS disponibili online quali WordPress,Joomla e Drupal. MySql è disponibile sotto forma di client a riga di comando e per renderlo piùutilizzabile è prassi comune affidarsi ad un tool dotato di interfaccia grafica, MySqlWorkbench, che permette di amministrare, modellare e sviluppare un database intutte le sue parti, minimizzando lo sforzo e il tempo impiegato. Quando vengono eseguiti in un computer con sistema operativo Linux, Apache,PHP e MySql formano il cosiddetto stack ”LAMP” (Linux, Apache, MySql, PHP),una struttura estremamente comune che unendo queste tecnologie forma un serverweb completo.4.6 Visual Studio CodePer la scrittura del codice è stato utilizzato l’editor freeware Visual Studio Code [13]di Microsoft, che include supporto per debugging, un controllo per Git integrato,Syntax highlighting, IntelliSense, Snippet e refactoring del codice; è inoltre ampia-mente personalizzabile grazie alla grande quantità di plugin disponibili tra cui ftp-kr [14], un’estensione che permette di collegarsi ad un server remoto tramite SFTPe caricare i codici sorgente man mano che vengono modificati, che si è dimostratamolto comoda in quanto il codice sorgente di Sugar è situato in una macchina Linuxcollegata in rete locale.VS Code è risultato essere un ottimo editor di testo che riesce a bilanciare bene laleggerezza sulle risorse di sistema con l’ampio ventaglio di funzionalità messe a di-sposizione allo sviluppatore e non a caso è l’ambiente di sviluppo più popolare nel2018 tra gli utenti di StackOverflow [15], il principale sito dedicato agli sviluppatori.4.7 Sugar CRMSia l’attuale piattaforma di gestione ticket che il sistema di suggerimento che verràrealizzato fanno parte di un’applicazione web CRM.Il CRM (acronimo per Customer Relationship Management) è, nella sua accezionepiù generale, un modello di business basato sulla capacità di • mantenere una relazione costante con i clienti acquisiti e potenziali, • comprendere i loro bisogni, • sviluppare prodotti e servizi che aumentino la customer satisfaction,e ha come obiettivo ultimo la fidelizzazione del cliente, fornendogli gli strumenti perinteragire con l’azienda e in particolar modo raccogliendo tutte le informazioni utilia riguardo, rendendole accessibili e condivise tra il personale dell’azienda stessa. Nello specifico, un software CRM è un’applicazione (spesso web) che implemen-ta tutte le caratteristiche necessarie per svolgere un’efficiente gestione delle relazionicon i clienti: attraverso un software CRM è possibile, ad esempio, monitorare le op-portunità commerciali in corso, lo stato degli ordini, le fatture, il calendario delleattività, le campagne di marketing in essere o i ticket aperti con il customer care.[16]Il software CRM sviluppato da Mediamind per InfoCert (e per altri clienti) si basa su 1 https://www.mysql.com/customers/

4.8. Smarty 15SugarCRM Community Edition (d’ora in poi denominato semplicemente ”Sugar”),una piattaforma CRM web open source scritta principalmente in PHP e JavaScriptche fornisce un punto di partenza per tutte le varie personalizzazioni richieste daiclienti di Mediamind. A livello utente, Sugar è formato da più ”moduli” che rappresentano tutte leentità logiche che ruotano intorno al customer relationship management, come adesempio le anagrafiche aziende e clienti, i contatti, le riunioni, le offerte, le opportu-nità, le email o i ticket.Generalmente un modulo si presenta sotto più viste, chiamate views: • ListView, in cui viene visualizzato l’elenco di tutti i record appartenenti a quel modulo; • EditView, che racchiude la creazione di un nuovo record e la modifica di un record già esistente; • DetailView, che mostra tutti i dettagli relativi ad un record.ed ognuno di questi record è memorizzato nella tabella del corrispondente moduloin un database.La maggior parte del lavoro di tirocinio si è concentrata proprio sul modulo relativoai ticket ricevuti e a tutto il conseguente workflow, chiamato MCE_CsDemands2 (Fi-gura 4.2).Per poter suddividere i ticket ricevuti in più aree tematiche è stato introdotto il mo-dulo MCE_checkTreeDoms che rappresenta un albero di categorie a tre livelli. Al li-vello più alto corrisponde la categoria più generica, identificata in uno dei principaliprodotti offerti da InfoCert (come LegalMail, LegalDoc, LegalCert, LegalInvoice oSecureDrive) mentre i rimanenti due livelli si articolano in diversi livelli di detta-glio per ogni prodotto. Per mantenere la gerarchia delle categorie nel database, ognicategoria possiede il codice identificativo della categoria padre (ad eccezione dellacategoria più generica). Attualmente la versione open source di Sugar non è più supportata dall’omoni-ma software house che l’ha prodotta, che ha preferito dedicarsi esclusivamente alleversioni a pagamento. Nonostante ciò, Mediamind continua a fornire supporto atutti i suoi clienti che utilizzano una versione personalizzata di Sugar. Dall’abban-dono di Sugar sono nate due alternative che hanno mantenuto in vita il progettonella sua forma open source: SuiteCRM [17] e SpiceCRM [18].4.8 SmartySugarCRM è stato progettato seguendo il paradigma MVC (Model, View, Control-ler), che prevede di mantenere separate la logica di business (i.e., il backend) dallalogica di presentazione (l’aspetto grafico di un sito web). Ciò viene facilitato dal-l’utilizzo di sistemi di web template, come Smarty [19], che permettono di definirela struttura della pagina in un file (con estensione .tpl) e la logica applicativa in unaltro file (di tipo PHP). Il vantaggio che porta questo modello, oltre alla maggioreleganza ed organizzazione della soluzione presentata, è che permette ai webdesi-gner e ai programmatori back-end di lavorare in modo indipendente senza curarsi,rispettivamente, della logica di programmazione e dell’interfaccia grafica del sito. 2 \"MCE\" è un acronimo per \"Mediamind Custom Edition\", il nome con cui vengono identificati tuttii moduli di Sugar aggiunti o fortemente modificati da Mediamind.

16 Capitolo 4. Strumenti utilizzati FIGURA 4.1: La pagina iniziale di SugarCRM per Infocert.

4.8. Smarty 17FIGURA 4.2: La ListView del modulo MCE_CsDemands formata dalla lista dei ticket e dai parametri per effettuare una ricerca.

18 Capitolo 4. Strumenti utilizzati Smarty consente la creazione di template HTML che possono contenere anchecostrutti logici quali cicli, if, modificatori di variabili, espressioni regolari, funzioni ecalcoli matematici.Un breve esempio di utilizzo è il seguente: File index.tpl<!DOCTYPE html><head> <title> {$title_text} </title></head><body> {$body_html}</body></html> File index.php<?phprequire_once('smarty/Smarty.class.php');$smarty = new Smarty();$smarty->template_dir = './templates/';$smarty->compile_dir = './templates/compile/';$smarty->assign('title_text', 'La prima pagina con Smarty');$smarty->assign('body_html', 'Un Hello world sarebbe banale, quindi<br> <h1>¡Hola, mundo!</h1>');$smarty->display('index.tpl');?>Durante lo sviluppo del progetto Smarty è stato utilizzato solo marginalmente, conla modifica di un template già esistente su Sugar.4.9 Apache SolrIl progetto finale si basa su Apache Lucene Solr [20], una piattaforma di ricerca en-terprise open source scritta in Java che permette una efficace indicizzazione di docu-menti (anche in formato Word e affini o PDF) e la relativa ricerca per parola chiavesu tutto il testo o con l’applicazione di filtri più o meno complessi. Nonostante Solr sia progettato per fornire funzionalità alla pari di un databaseNoSQL, sia scalabile e fortemente tollerante ai guasti, durante questo tirocinio è statoutilizzato per le sue caratteristiche più basilari, quali l’indicizzazione e la ricerca didocumenti di solo testo con dei relativi metadati ma soprattutto per la sua funzionechiamata \"MoreLikeThis\" che, utilizzando tecniche basate su quelle descritte nel pa-ragrafo 2 (chiaramente perfezionate ed ottimizzate), permette di ottenere un elencodi documenti tra quelli salvati affini ad uno dato (che può essere anch’esso un docu-mento caricato su Solr o anche un documento esterno), insieme al relativo punteggiodi somiglianza. Inoltre Solr possiede di default una lista di sinonimi e stopword del-le lingue più diffuse, in modo da poter svolgere in automatico un’ottimizzazione deltesto, eliminando le stopword dai documenti e raggruppando ad esempio tutte le

4.9. Apache Solr 19possibili coniugazioni dei verbi più comuni in una unica \"parola\" logica. Tra le ca-ratteristiche da riportare troviamo infine i tokenizer, funzioni che spezzano i testi inunità lessicali considerando gli spazi bianchi e la punteggiatura come delimitatori e,opzionalmente, raggruppano più parole che formano un concetto unico nello stessotoken. Un server Solr si articola in uno o più core, istanze che rappresentano ciascuna unmotore di ricerca, ognuno con le proprie impostazioni. Nonostante sia dotato di unacomoda interfaccia grafica, per poter personalizzare al meglio un core è necessarioagire su due file: solrconfig.xml e schema.xml. Nel primo vengono definiti tutti i pa-rametri per configurare Solr3, mentre nel secondo vengono descritti tutti i campi deidocumenti che verranno indicizzati in quel core, in maniera simile alla definizionedelle colonne di un database. Dal punto di vista tecnico, Solr è una web application che resta in ascolto in unaporta specifica (di default la 8983). Una richiesta, o query, a Solr viene effettuatatramite una richiesta HTTP di tipo GET o POST che verrà processata dal relativorequest handler, un plugin che definisce la logica eseguita per ogni richiesta. Il requesthandler più usato è il ”SearchHandler” che permette di interrogare Solr fornendogliuna query come nella seguente richiesta GET: http://localhost:8983/solr/select?q=id:123456789dove select indica il tipo di RequestHandler (in questo caso SearchHandler) e il para-metro q racchiude la query che è rappresentata dalla richiesta di un documento cheabbia il campo ’id’ uguale a 123456789.La funzione \"MoreLikeThis\" descritta in precedenza è implementata proprio dall’o-monimo RequestHandler, abbreviato in mlt. Un esempio di una risposta in JSON diSolr per una collezione di poesie è la seguente, dove la sequenza ”\n” rappresentaun carattere di ”a capo”:{ \"responseHeader\":{ \"status\":0, \"QTime\":114, \"params\":{ \"q\":\"id:123456789\", \"_\":\"1540747977265\"}}, \"response\":{\"numFound\":1,\"start\":0,\"docs\":[ { \"id\":\"123456789\", \"titolo\":[\"La pioggia nel pineto\"], \"autore\":\"Gabriele D'Annunzio\", \"testo\":[\"Taci. Su le soglie\ndel bosco non odo\nparole che dici\numane; ma odo\nparole più nuove\nche parlano gocciole e foglie\nlontane. \nAscolta. ... \"], \"_version_\":1615591344860823552}] }} Solr si è dimostrato uno strumento estremamente potente e semplice da usaree non sorprende vedere tra i suoi utilizzatori nomi come eBay, Ticketmaster, Insta-gram, Netflix, DuckDuckGo e Disney. 3 Il solrconfig.xml di default può essere scaricato dahttps://github.com/apache/lucene-solr/blob/master/solr/server/solr/configsets/_default/conf/solrconfig.xml



215 ProgettazionePer la realizzazione del progetto sono stati tentati due approcci, al fine di valutarequale sia il più conveniente in fatto di prestazioni, affidabilità e leggerezza: il pri-mo servendosi di una libreria di feature extraction ed elaborando tutto in PHP, l’altroservendosi di Solr, delegando ad esso tutto il processo di tokenizzazione e vettoriz-zazione. Questa seconda strada è stata quella che successivamente si è dimostrataottimale e quindi implementata per la consegna al cliente. Considerando che l’analisi di somiglianza potrebbe impattare in modo più o me-no trascurabile sul caricamento della pagina (si tratta pur sempre di elaborazioniche richiedono un tempo maggiore di zero) e che un elenco di suggerimenti non èuna informazione primaria durante la visualizzazione di un ticket (può pertanto es-sere visualizzata in ritardo rispetto alla pagina completa, o non essere visualizzataaffatto), in entrambe le soluzioni tentate si è ritenuto preferibile effettuare tutte leelaborazioni necessarie in modo asincrono rispetto al caricamento della pagina, co-me indicato da uno dei requisiti funzionali nel paragrafo 3.1, proprio per evitare dirallentarlo, utilizzando quindi una chiamata AJAX per richiedere e successivamenteottenere i risultati da uno script PHP.5.1 Soluzione in PHPConsiderando il modello a spazio di vettori descritto nel paragrafo 2.2, un primoapproccio è stato quello di costruire una matrice per tutti i ticket presenti nella kno-wledge base, per poi confrontare ciascuno dei vettori con quello di un ticket appenaricevuto, restituendo infine l’elenco dei ticket che hanno maggior punteggio di simi-litudine. Idealmente nel database sarebbe stata aggiunta una colonna che riportasseil valore booleano true se il ticket fosse stato contenuto nella knowledge base.Questa soluzione non é stata ulteriormente sviluppata in quanto sin dai primi testdi prototipo sono emersi notevoli limiti legati all’utilizzo di memoria nel server ed èstata quindi immediatamente abbandonata a favore della soluzione integrante Solr.5.2 Soluzione in PHP+SolrPer quanto riguarda l’interfaccia utente, nella DetailView del modulo MCE_CsDemandsè stato aggiunto un pannello che contiene l’elenco dei ticket restituiti da Solr e il rela-tivo link, la descrizione e data. Questo pannello riporta la data a cui è aggiornata lacache e dà la possibilità all’utente di effettuare un refresh dei dati. È presente inoltreun pannello di impostazioni per personalizzare i risultati come richiesto dal requisi-to funzionale numero 4 al capitolo 3.1.È necessario che sia avviato un server Solr (anche nello stesso server in cui è contenu-to Sugar) che esponga il RequestHandler ”mlt” e indicizzi ogni ticket con i seguenticampi:

22 Capitolo 5. Progettazione • ID del ticket, • ID del cliente a cui è riferito, • ID delle tre categorie a cui il ticket appartiene, • Testo della richiesta ricevuta, • Risposta data al cliente, • Titolo del ticket, • Data in cui è stato ricevuto, • Lista di tutti gli utenti e tutti i team di assistenza che hanno contribuito alla risoluzione del ticket.Il RequestHandler mlt dovrà basare la propria valutazione di similitudine solo sulladescrizione della richiesta e sulla risposta fornita dall’assistenza.Dopo che il caricamento della pagina sarà completato, verrà inviata una richiestaAJAX ad uno script PHP che, ricevendo l’id del ticket visualizzato, recupererà daldatabase tutti i dettagli necessari all’elaborazione. Successivamente effettuerà unarichiesta mlt a Solr inviando la richiesta del ticket, ricevendo un JSON contenente unelenco di ticket che hanno il testo della richiesta e della soluzione semanticamentesimile a quello passato, ognuno con il rispettivo punteggio di similitudine. Questopunteggio verrà ulteriormente elaborato, aumentandolo di una quantità arbitrarianel caso in cui entrambi i ticket appartengano alla stessa categoria o allo stesso clien-te e di una quantità definita da una funzione matematica in base a quanto è vecchioil ticket.Successivamente verrà salvata come cache su disco una copia del JSON insieme alladata e ora in cui è stato ricevuto, che verrà utilizzata nel caso di ulteriori richieste(cioè di ulteriori visualizzazioni della DetailView) per lo stesso ticket.Infine il PHP risponderà alla richiesta con l’elenco dei ticket correlati opportuna-mente formattato.Uno schema esplicativo di questa soluzione è riportato in figura 5.1: 1. Dopo che la pagina è stata caricata, uno script JavaScript effettua una richiesta AJAX a una pagina PHP. 2. Lo script PHP controlla se nella cache locale del server è presente una risposta già data per quel ticket: in tal caso, restituisce quella. 3. Ottiene dal database i dettagli del ticket. 4. Effettua una query \"MoreLikeThis\" a Solr con il testo del ticket visualizzato. 5. Solr risponde con una lista di ticket simili. 6. Il PHP salva su disco il file JSON ricevuto da Solr. 7. Elabora il punteggio dei ticket ricevuti e risponde alla richiesta AJAX con l’HTML dei ticket simili da visualizzare nella pagina. Per quanto riguarda la creazione della knowledge base, verrà aggiunta nell’E-ditView del modulo MCE_CsDemands un flag che indica se il ticket dovrà essere omeno aggiunto tra quelli ritenuti rilevanti e indicizzati su Solr. In fase di chiusuradel ticket verrà eseguito uno script che lo invia a Solr, per renderlo disponibile aduna futura consultazione.

5.2. Soluzione in PHP+Solr 23SugarCRM 192.168.0.1/index.php?module=MCE_CsDemands Ticket Correlati Ticket 1 Ticket 2 Ticket 3 Ticket 417 43 6 25FIGURA 5.1: Schema esemplificativo del funzionamento della soluzione utilizzante Solr



256 ImplementazioneIl progetto implementato è quello che si interfaccia con Solr, descritto nella sezione5.2.L’ambiente di sviluppo adottato da Mediamind è composto da vari server (Windo-ws e Linux) connessi in una rete locale che mantengono una copia funzionante ditutti i CRM e una versione ridotta dei database dei propri clienti, in modo da potereffettuare modifiche e test in modo agevole e isolato dai server dei clienti. In questocapitolo verranno usati degli indirizzi IP fittizi per riferirsi agli indirizzi dei server.Le parti di codice più consistenti sono state spostate in appendice per consentire unalettura più fluida e verranno richiamati quando opportuno.6.1 Back-endIl back-end si compone di un server Solr e uno script PHP che gestisce le comunica-zioni tra Solr e il browser web ed effettua tutte le elaborazioni necessarie.6.1.1 SolrPer poter avviare una istanza di Solr è stata scaricata la versione per Linux dal sitodi Apache1 ed è stata installata semplicemente estraendo il contenuto scaricato nellaroot di sistema (la scelta del percorso è solo per comodità).Successivamente con il comando /solr/bin/solr start viene avviato il servizioSolr ottenendo il messaggio di conferma ”Started Solr server on port 8983. Happysearching!”.Nella cartella di Solr server/solr è stata creata la directory infocert e al suo internoè stata copiata la cartella conf da server/solr/configsets/_default contenente ifile di configurazione di default per un nuovo core, tra cui solrconfig.xml in cui vaaggiunto il RequestHandler ”MoreLikeThis”, non attivo di default, insieme agli altrigià presenti, aggiungendo il seguente frammento in formato XML:<requestHandler name=\"/mlt\" class=\"solr.MoreLikeThisHandler\"> <lst name=\"defaults\"> <str name=\"mlt.fl\">description, risposta</str> <str name=\"mlt.match.include\">false</str> <str name=\"mlt.minwl\">3</str> <str name=\"rows\">10</str> <str name=\"mlt.mintf\">2</str> <str name=\"mlt.mindf\">3</str> </lst></requestHandler> 1 https://www.apache.org/dyn/closer.lua/lucene/solr/7.5.0

26 Capitolo 6. Implementazioneche ha come attributi, nell’ordine: • fl: rappresenta i campi in cui ricercare testo simile (description e risposta) che verranno successivamente definiti in fase di creazione del core. • Match.include: indica se ritornare o meno un campo che contiene il documento trovato in caso di una query. • Minwl: indica che verranno ignorate le parole di lunghezza inferiore a 3 carat- teri. • Rows: chiede di ritornare al massimo 10 ticket simili. • Mintf: indica che nel testo passato verranno ignorate le parole che non compa- iono almeno 2 volte. • Mindf: indica che verranno ignorate le parole che non compaiono in almeno 3 ticket.Questi parametri definiscono come Solr effettuerà l’analisi dei documenti ai fini del-l’assegnazione del punteggio di similitudine, e quindi sui risultati restituiti. I valorisono stati assegnati in via indicativa, e potranno essere modificati per migliorare laqualità dei suggerimenti forniti.Successivamente, dalla pagina di amministrazione raggiungibile dalla porta 8983del server, all’indirizzo 192.168.0.1:8983/solr è stato creato un nuovo core checonterrà la collezione di ticket per la knowledge base, inserendo ”infocert” comename e instanceDir (figura 6.1). A questo punto è stato definito lo schema, ovverol’insieme dei campi e proprietà che verranno memorizzati per ogni ticket caricato suSolr. Per farlo è necessario spostarsi nella pagina ”Schema” del core appena crea-to sulla dashboard di amministrazione nella pagina web ed aggiungere i seguenticampi su ”Add Field” (figura 6.2):”name” ”field type” Descrizione Opzioniid String Id del ticket flag su termVectorsparent_id String Id del cliente richiedente flag su termVectorsid_cat1 String Categoria di appartenenza genericaid_cat2 String Sotto-categoria di primo livello flag su multiValuedid_cat3 String sotto-categoria di secondo livello flag su multiValuedrichiesta text_general Testo della richiesta del ticketrisposta text_general Risposta data al clientename text_general Titolo del ticketde_day pint Giorno della data in cui è stato creato il ticketde_month pint Mese della data in cui è stato creato il ticketde_year pint Anno della data in cui è stato creato il ticketassigned_users String Id degli utenti che hanno contribuito alla risoluzionesecuritygroups String Id dei team che hanno contribuito alla risoluzione L’opzione multiValued indica che quel campo potrà contenere più di un valore,come se fosse una lista, mentre l’opzione termVectors indica che quel campo dovràessere vettorizzato per poter avere migliori prestazioni quando verrà usato comecampo di ricerca in una query MoreLikeThis, come descritto nella documentazioneufficiale2. Nel nostro caso, infatti, saranno vettorizzati gli stessi campi implicati nellaricerca di ticket simili.La data di creazione del ticket è stata suddivisa in giorno, mese ed anno per renderepiù agevole un possibile filtro di ricerca implementabile nel futuro. 2 https://lucene.apache.org/solr/guide/7_4/morelikethis.html#how-morelikethis-works

6.1. Back-end 27 FIGURA 6.1: Creazione di un nuovo core su Solr. FIGURA 6.2: Aggiunta di un campo nel nuovo core.

28 Capitolo 6. Implementazione6.1.2 PHPUna volta che l’istanza di Solr è attiva e configurata, dev’essere popolata con deiticket. Non avendo a disposizione il database reale del cliente sono stati inseriti neldatabase e successivamente su Solr dei ticket copiati dalle FAQ di assistenza di In-foCert3, in aggiunta ai ticket di test con descrizioni fittizie già presenti nel database.Per fare ciò, è stata creata una funzione PHP che invii a Solr un generico ticket pre-sente nel database (in modo da poterla riutilizzare successivamente) e richiamataper un certo numero di ticket.Nella funzione loadSolr, consultabile in appendice nella sezione A.1, vengono otte-nuti dal database tutti i dettagli relativi a un singolo ticket. Sebbene molti sianogià presenti nella DetailView, è stato preferito ri-ottenerli per evitare un complessolavoro di navigazione nell’HTML della pagina, dato che alcune query sarebbero co-munque risultate necessarie.Nelle righe 15 e 19 viene eliminato tutto il testo racchiuso tra i caratteri ”===”. Que-sto perché nel database i campi resolution e risposta sono salvati inserendo anchel’utente e la data in cui sono stati scritti o modificati, ad esempio”=== admin (Administrator) - 31/08/2018 09:21 ===” (un esempio è visibile nel-la schermata della DetailView del progetto completato, figura 6.4).Successivamente viene ottenuta la lista delle categorie a cui appartiene il ticket, dallapiù generica alla più dettagliata, che verrà usata per ricostruire l’albero della gerar-chia, utilizzando la tabella MCE_CsDemand_MCE_checkTreeDom che lega tra loro iticket (MCE_CsDemands) e le categorie (MCE_CheckTreeDoms).Infine il JSON contenente i dettagli del ticket viene passato alla funzione caricaJson-Solr che, sfruttando la libreria cURL presente in PHP, invia al server di Solr il JSONcontenente i dettagli del ticket e la richiesta di aggiungerlo alla collezione. Nel det-taglio, l’url a cui inviare la richiesta è la concatenazione tra l’url base di Solr, salvatoin un array associativo globale come<?php$sugar_config = array( ... 'solr_url' => '192.168.0.1:8983/solr/infocert/'... );?> e l’url del RequestHandler ”update” di tipo JSON. Altre opzioni dell’oggettocURL sono: • CURLOPT_HTTPHEADER: imposta l’header HTTP, in questo caso definendo solo il tipo del contenuto (JSON); • CURLOPT_POST: definisce che questa richiesta sarà di tipo POST; • CURLOPT_POSTFIELDS: definisce quale sarà il contenuto della POST; • CURLOPT_TIMEOUT: indica che dopo 10 secondi senza ricevere risposta dal server lo script deve chiudere la connessione; • CURLOPT_RETURNTRANSFER: true per ritornare la risposta come stringa, senza scriverla direttamente in output.Infine lo script invia la richiesta a Solr che può considerarsi conclusa con successo serisponde con il valore del campo ”status” uguale a zero nell’header della risposta. 3 https://help.infocert.it/

6.1. Back-end 29 Ora che Solr contiene una certa quantità di ticket, si può procedere ad implemen-tare la comunicazione tra Solr e Sugar per ottenere la lista di ticket simili desiderata.Prima di proseguire nell’implementazione del backend, però, è necessario imposta-re un nuovo entryPoint di Sugar: come misura di sicurezza è definita una lista di filePHP, chiamati appunto entryPoint, che è consentito richiamare dal web, mentre altridevono rimanere protetti e disponibili esclusivamente ad uso interno (ad esempiotutti i file che descrivono classi o interfacce). Questa è una funzionalità di Sugar attaad evitare l’esecuzione (volontaria o meno) di certi script. Per fare ciò è sufficienteaggiungere nell’array definito nel fileinclude/MVC/Controller/entry_point_registry.php il valore:<?php$entry_point_registry = array( ... 'getmlt'=> array( 'file' => 'modules/MCE_CsDemands/getMlt.php', 'auth' => false));?>che imposta come un entryPoint lo script PHP che risponderà alle richieste AJAX.Ora è possibile iniziare a scrivere la logica applicativa: è stato creato un nuovo script,getMlt.php, che elaborerà tutta la comunicazione tra il CRM e Solr. Consideran-do che verrà implementato un pannello di personalizzazione che può modificare ilcomportamento dello script (favorendo o meno certi criteri, come definito nel requi-sito 4 del capitolo 3), inizialmente verranno valutati i parametri ricevuti nella reque-st, verificando quali sono presenti ed agendo di conseguenza. I parametri accettatisono: • id_ticket: l’id del ticket di cui si vuole ottenere la lista di ticket simili. È l’unico parametro obbligatorio; • refreshCache: true se si vuole forzare la richiesta a Solr senza utilizzare la cache locale (false di default); • cacheOn: true di default, indica se utilizzare o meno il meccanismo di ca- ching. Questo parametro non è usato, ma è stato aggiunto in vista di possibili modifiche future; • max_ticket: il numero massimo di ticket che verranno visualizzati. Di default è impostato a 5 e deve essere comunque minore del numero di ticket ritornati da Solr definito nel RequestHandler descritto nel capitolo 6.1.1; • pref_same_client: indica se favorire o meno i ticket provenienti dallo stesso cliente (true di default); • pref_same_cat: indica se favorire o meno i ticket provenienti dalla stessa cate- goria (true di default); • pref_my_team: indica se favorire o meno i ticket risolti dal team a cui appar- tiene l’utente che sta visualizzando il ticket (false di default); • prefer_recent: indica se favorire o meno i ticket recenti (false di default); Nella prima parte dello script (presente nell’appendice alla sezione A.2.1) trovia-mo nella prima riga la misura di sicurezza descritta poco fa relativa agli entryPoint:se per questo file non è definita una ”entrata” di Sugar viene arrestata l’esecuzione

30 Capitolo 6. Implementazionedella web application. Questo è un controllo eseguito in ogni file di Sugar, ma aven-dolo incluso nel entry_point_registry.php non genererà alcun tipo di errore.Alla riga 6 viene utilizzato un oggetto di Sugar, UserPreference, che mantiene sianella sessione corrente che nel database un elenco di preferenze per ogni utente co-me una coppia chiave => valore, accessibili attraverso i metodi setPrefence(chiave,valore) e getPreference(chiave). Questo è stato usato per memorizzare le preferenze divisualizzazione senza dover utilizzare cookies, sessioni o ulteriori metodi.Successivamente, per ogni parametro presente nella request viene memorizzato ilrelativo valore nelle UserPreference. Se quel parametro non è presente viene usatoquello salvato nelle UserPreference, se c’è, altrimenti viene usato il valore di default.Alla riga 50 vengono scritti dei campi nascosti nella pagina HTML che contengono ivalori aggiornati delle preferenze, codificati in JSON: verranno letti dal JavaScript sel’utente apre il pannello di impostazioni, in modo da mostrare i valori attualmentememorizzati per ognuna delle preferenze. Lo script prosegue con le istruzioni presenti nella sezione A.2.2 dell’appendice:per chiarezza l’algoritmo è stato scomposto nelle principali componenti che verran-no descritte più avanti.Inizialmente viene controllato se l’id passato è diverso da null o undefined: questoperché in caso di problemi nell’ottenere l’id del ticket il JavaScript che ha chiamatoquesta pagina ritorna un valore indefinito (undefined, appunto), che nel momen-to della richiesta GET viene convertito in testo letterale; inoltre se non è presente ilparametro id_ticket viene impostato a null. Nel caso in cui queste condizioni nonvengano soddisfatte lo script termina con il messaggio a riga 36, anche se è altamen-te improbabile che accada, dato che verrà riempito direttamente dal JavaScript.Viene poi definito il percorso in cache per il ticket in oggetto, che consiste in unacartella dedicata cacheMlt contenente tanti file JSON, ognuno avente come nome l’iddel ticket a cui si riferisce, in modo da rendere agevole la ricerca. Verrà quindi estrat-to il file in cache se esiste, se è attivo l’utilizzo della cache e se non ho richiesto diaggiornarla. Altrimenti verrà inviata una richiesta a Solr che restituirà anch’esso unfile JSON. Se non si verificano errori durante la richiesta vengono rielaborati i pun-teggi restituiti da Solr, viene inviata la risposta con la lista di ticket formattati in unatabella ed eventualmente viene salvato il file JSON nella cache, se non esiste. Tragli errori che possono occorrere c’è l’errore durante la richiesta cURL a Solr, un er-rore interno di Solr che restituisce una risposta vuota oppure l’impossibilità di Solrdi trovare ticket correlati secondo i parametri definiti nel RequestHandler. Questeeventualità vengono gestite con i messaggi d’errore rispettivamente alle righe 33, 30e 26 ed è proprio quest’ultima quella che può verificarsi più comunemente. Con le istruzioni della sezione A.2.3 in appendice, in modo analogo al filecaricaSolr.php, vengono estratti dal database tutti i dettagli relativi al ticket in esa-me, ricreando la gerarchia delle categorie e rimuovendo le aggiunte operate da Sugarsulla descrizione del ticket, che verrà passata alla funzione sendMltJson(descrizione):

6.1. Back-end 311 File getMlt.php2 <?php3 function sendMltJson($testo) {4 global $sugar_config;5 $param='fl=id,description,score,name,de_year,de_month,de_day';6 $url = $sugar_config['solr_url'] . \"mlt?$param&wt=json\";7 $ch = curl_init(); // Crea la risorsa CURL8 curl_setopt($ch, CURLOPT_URL, $url);9 curl_setopt($ch, CURLOPT_HTTPHEADER,10 [\"Content-type: text/plain; charset=utf-8\"]);11 curl_setopt($ch, CURLOPT_POST, true);12 //inserisco il testo del ticket nel body della richiesta post:13 curl_setopt($ch, CURLOPT_POSTFIELDS, $testo);14 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);15 $data = curl_exec($ch);16 $jsonArray = json_decode($data, true);17 if (curl_errno($ch)) {18 print \"curl_error: \". curl_error($ch);19 return false;20 } else {21 curl_close($ch);22 $jsonArray['lastUpdate'] = date('d/m/y H:i');23 return $jsonArray;24 }25 } Analogamente alla funzione caricaJsonSolr(json), anche questa effettua una richiesta a Solr specificando però come URL il RequestHandler mlt e la lista di campi desiderati tramite il parametro fl che contiene, tra l’altro, il campo ”score”, calcolato in automatico da Solr durante le query MoreLikeThis. In caso di errori ritorna il booleano false, altrimenti aggiunge all’array relativo al json ricevuto il timestamp attuale, in modo da memorizzare e quindi visualizzare la data a cui è aggiornato il file json che verrà poi salvato in cache, e lo restituisce. Avendo un array con la lista di ticket simili, ottenuto da Solr o dalla cache, è possibile procedere all’analisi e modifica dei punteggi, inviando la risposta AJAX e concludendo l’esecuzione dello script, di cui è riportata l’ultima parte nell’appendi- ce al capitolo A.2.4. Per ogni ticket ritornato da Solr vengono troncate la descrizione e il titolo per evita- re problemi di visualizzazione (le istruzioni corrispondenti non sono state riportate per brevità) e viene ricomposta la data dalle tre componenti, in modo da poter cal- colare quanti giorni prima è stato creato il ticket: new DateTime() ritorna infatti la data attuale. È stata inoltre definita la funzione f (x) = 365/(x + 365) per ottene- re un numero minore di 1 che decresca asintoticamente all’aumentare dei giorni di vecchiaia del ticket (rappresentati dalla variabile indipendente x) che verrà aggiunto al punteggio calcolato da Solr nel caso in cui l’utente abbia scelto di favorire i ticket recenti. Successivamente verranno confrontati gli id delle categorie e del team del ticket visualizzato con quelli di ognuno dei ticket ritornati da Solr, aggiungendo allo sco- re l’eventuale peso definito all’inizio dello script (che può essere zero nel caso in cui l’utente abbia espresso la preferenza di non favorire uno di questi parametri). Inoltre

32 Capitolo 6. Implementazione FIGURA 6.3: Grafico della funzione utilizzata per scegliere il punteg- gio aggiunto in base alla vecchiaia del ticket, con un range di due anni.il peso aggiunto per i ticket con la stessa categoria di quello analizzato cresce linear-mente con la profondità della categoria nella gerarchia di categorie: questo per daremaggior rilevanza a ticket che presentano maggior affinità di contesto. Infine i ticketvengono preparati per la visualizzazione: se i punteggi di Solr sono stati modificati,la lista di ticket dovrà essere ordinata per punteggio in modo decrescente tramiteuna semplice funzione ad-hoc, compare_score, che rispetti le specifiche del metododi ordinamento standard di PHP: dati due ticket, dovrà ritornare 0 nel caso i duepunteggi siano uguali, oppure un numero negativo o positivo se il primo punteggioè, rispettivamente, minore o maggiore del secondo. Dato che però si desidera ordi-nare i ticket in modo decrescente è stata costruita una funzione che si comporta inmodo opposto:<?phpfunction compare_score($a, $b) { if ($a['score']==$b['score']) return 0; return ($a['score']>$b['score'])? -1:1;}?> Vengono quindi mantenuti i migliori ticket da visualizzare e per ognuno vienecreata una riga nella tabella con il link al ticket e la data di creazione. Infine vienestampata la data a cui è aggiornato il JSON da cui è stata ottenuta la lista e vieneinviato tutto al front-end tramite l’istruzione echo. Al termine di tutto il processoviene scritto in un file su disco il JSON ricevuto nel caso in cui non esista o se l’u-tente ha forzato un refresh. Per evitare di riempire il disco di file di cache vengonocancellati tutti quando si supera un limite massimo di 250 file. Infine, per effettuare il caricamento in Solr dei ticket chiusi è stato modificato il fi-le custom/modules/MCE_CsDemands/MCE_CsDemandsWflowLogicHook.php che esegue

6.2. Front-end 33tutta una serie di operazioni prima e dopo il salvataggio nel database di un ticket,utilizzando rispettivamente le funzioni beforeSave e afterSave. In quest’ultima èstato aggiunto il codice seguente che carica su Solr il ticket appena chiuso se l’utenteha selezionato la corrispondente checkbox, inserita nel template Smarty della vistaEditView. file MCE_CsDemandsWflowLogicHook.php<?php...function after_save(&$bean, $event, $arguments) {... if(!empty($bean->resolution)){ // ticket risolto if(!empty($bean->inserisci_solr)) { //checkbox true require_once(\"modules/MCE_CsDemands/caricaSolr.php\"); loadSolr($bean->id); } ... }}?> In modo analogo ad un altro campo rappresentato da una checkbox (nello spe-cifico, se il cliente desidera o meno una risposta via email), l’oggetto $bean conterràla proprietà inserisci_solr se la relativa checkbox è selezionata, altrimenti la pro-prietà sarà vuota. Lo script PHP richiamerà quindi la funzione loadSolr descritta inprecedenza per inviare il ticket a Solr. 6.2 Front-end Il front-end è stata la parte che ha richiesto un minor numero di ore di lavoro e si è articolata tra la costruzione del pannello che mostri i ticket nel DetailView e la scrittura del codice JavaScript che effettua la chiamata AJAX. 6.2.1 JavaScript Il sorgente JavaScript è formato da una parte che inva la richiesta AJAX alla pagina PHP e da una parte che visualizza un pannello di impostazioni che l’utente potrà usare per personalizzare i criteri con cui vengono visualizzati i ticket. La richiesta AJAX è molto simile a quella riportata nell’esempio al capitolo 4.3:1 function sendMlt(params) {2 var xhttp = new XMLHttpRequest();3 xhttp.onreadystatechange = function() {4 if (this.readyState == 4 && this.status == 200) {5 document.getElementById(\"correlatiTable\").innerHTML = this.responseText;6}7 };8 var param = window.location.search.split('&');9 var id_ticket;10 for(i=0; i<param.length; i++){11 if(param[i].startsWith(\"record=\"))12 id_ticket = param[i].replace(\"record=\", \"\");

34 Capitolo 6. Implementazione13 }14 var urlBase = \"index.php?entryPoint=getmlt&id_ticket=\"+id_ticket;15 urlBase+=params;16 xhttp.open(\"GET\", urlBase, true);17 xhttp.send();18 }Questa funzione viene richiamata ad ogni refresh della pagina e ad ogni salvataggiodelle impostazioni da parte dell’utente, per aggiornare i ticket visualizzati sulla basedei nuovi criteri.Dato che mentre si visualizza un ticket l’URL della pagina contiene l’id del recordvisualizzato, viene estratto e inserito come parametro GET nell’URL che verrà in-viato alla pagina getMlt.php, insieme ad altri eventuali parametri derivanti dalleimpostazioni, ad esempio il numero massimo di ticket da visualizzare, definiti nelparametro di ingresso della funzione params.Quando lo script PHP risponde alla richiesta AJAX, la funzione sendMlt scrive larisposta ricevuta nella tabella correlatiTable, definita nel template, attraverso l’i-struzione alla riga 5. Non sono necessarie ulteriori operazioni perché la rispostaottenuta da getMlt.php è già opportunamente formattata in HTML. Per visualizzare il pannello di impostazioni, invece, è stata usata una libreriaesterna disponibile su GitHub chiamata ”quicksettings” [21], che permette la crea-zione in modo semplice e rapido di pannelli di impostazioni più o meno complessi.La funzione showSettings (si veda la sezione A.4 in appendice) viene invocata ognivolta che l’utente clicca sul pulsante delle impostazioni nel pannello dei ticket corre-lati e per ognuno dei criteri esistenti ottiene il valore dai campi hidden scritti in pre-cedenza dal PHP in JSON e lo usa come valore da visualizzare. Alla pressione deltasto ”Ok” verrà infine inviata una richiesta alla pagina getMlt.php con i parametriscelti dall’utente.6.2.2 DetailViewNel template Smarty del DetailView, situato inmodules/MCE_CsDemands/DetailView.tpl, è stato aggiunto un nuovo pannello espan-dibile, analogo a quelli già esistenti, il cui codice è riportato in appendice nella se-zione A.5.Il pannello creato è identificato con un numero progressivo in modo da poter usarele funzioni già esistenti che lo possano espandere e comprimere. È stato aggiun-to un pulsante per il refresh che invia una richiesta a getMlt.php con il parametrorefreshCache impostato a true e un pulsante per le impostazioni che visualizzi ilrelativo pannello. Infine, al caricamento della pagina viene eseguita una chiamata agetMlt.php senza alcun parametro per ottenere la lista da visualizzare. Al termine dell’implementazione di frontend e backend la DetailView si presentacome in figura 6.4.

6.2. Front-end 35FIGURA 6.4: DetailView con il pannello completato dei ticket correlati e il pannello delle impostazioni visibile.

36 Capitolo 6. Implementazione6.2.3 EditViewPer caricare su Solr un ticket al momento della sua chiusura è sufficiente aggiungereuna checkbox nell’EditView del modulo MCE_CsDemands che l’utente può utilizzareper segnalare il ticket come ”da caricare”. Per farlo è stato aggiunto il seguenteframmento di codice in modules/MCE_CsDemands/EditView.tpl:<td id=\"_label\" scope=\"col\" width=\"12.5%\" valign=\"top\"> Inserisci nella knowledge base:</td><td width=\"37.5%\" valign=\"top\"> <input type=\"checkbox\" id=\"inserisci_solr\" name=\"inserisci_solr\" value=\"1\"></td>Che nel browser risulterà come in figura 6.5. FIGURA 6.5: EditView con la checkbox per l’inserimento su Solr.

6.3. Prototipo della soluzione non realizzata 376.3 Prototipo della soluzione non realizzataNella sezione A.3 dell’appendice è riportato il codice del primo prototipo utilizzan-te solo PHP che è stato scartato: la grande quantità di di ticket da memorizzare eanalizzare ha infatti portato a richiedere circa 500MB di memoria RAM nel serverad ogni esecuzione, in particolare durante il processo di vettorizzazione, un valo-re inaccettabile considerando le centinaia di richieste contemporanee che possonopervenire al server di un customer care. Nonostante le scarse prestazioni, la libreriautilizzata ”PHP-ML”[22] si è dimostrata di facile utilizzo ed estremamente versatilee resta un valido strumento da tenere in considerazione per un utilizzo in futuro.Nel dettaglio, questa libreria mette a disposizione delle funzioni per l’utilizzo del-le tecniche di machine learning più comuni quali classificazione (classificazione avettore di supporto, k-Nearest Neighbors e Naive-Bayes), regressione lineare (LeastSquares e a vettore di supporto), clustering (K-means e DBSCAN), metriche di ac-curacy, matrice di confusione, reti neurali, selezione ed estrazione di caratteristiche(di cui fanno parte le funzioni di analisi del testo utilizzate) e tutti gli strumenti utiliper estrarre e pre-processare dati (lettura di file .csv, classi di array, normalizzazionestatistica dei valori in un dataset e suddivisione casuale dei dati per le reti neurali).Nell’algoritmo inizialmente viene riempito un array con tutte le descrizioni e le riso-luzioni dei ticket presenti nella knowledge base che verrà usato per creare i vettoriTF-IDF per ogni ticket. Concatenare descrizione e risposta non è un problema perchénella rappresentazione bag of word l’ordine delle parole viene perso. Viene riempitoinoltre un secondo array che contiene l’id del cliente, della categoria più interna e ladescrizione per poi visualizzarne l’inizio nella lista che verrà ritornata.Successivamente un elenco di stopword viene usato per istanziare un oggetto dellaclasse TokenCountVectorizer che, per ogni ticket, crea il rispettivo vettore conte-nente la frequenza per ogni termine; i vettori di frequenze verranno poi trasformatiin vettori di punteggi TF-IDF da un oggetto della classe TfIdfTransformer. Questedue classi sono importate dalla libreria PHP-ML nelle righe iniziali dello script.Ora che abbiamo i vettori di punteggi TF-IDF li possiamo confrontare con il ticketvisualizzato: ne viene creato il rispettivo vettore in modo analogo, senza però richia-mare la funzione fit: questa funzione infatti definisce la dimensione dello spaziovettoriale in base al numero di parole trovate nel corpus di ticket e va richiamatasolo durante l’analisi dei ticket nella knowledge base.Tramite la funzione cosine della libreria viene ottenuto il punteggio di similitudi-ne tra il ticket visualizzato e ognuno dei ticket in elenco, che verrà eventualmenteaumentato in caso di coincidenza di cliente o categoria. Infine l’elenco di ticket vie-ne ordinato in modo decrescente rispetto al punteggio di similitudine e vengonovisualizzati i migliori 5. Le limitazioni maggiori riscontrate in questo algoritmo risiedono nelle istruzionidi fit e transform che hanno richiesto una quantità di RAM oltre i limiti impostidal server PHP già per un numero relativamente basso di ticket (circa 5.000). Ri-spettivamente queste funzioni servono per costruire il dizionario di termini (fit) etrasformare (transform) il testo in un vettore. [23]È stato quindi ritenuto preferibile concentrare ore di lavoro nello sviluppo di una so-luzione più elaborata ma efficiente, piuttosto di tentare di migliorare le prestazionidi una soluzione già sottodimensionata.



397 ConclusioniAl momento della scrittura di questa relazione il progetto non è ancora stato conse-gnato al cliente per dare priorità ad altre modifiche e correzioni a Sugar a cui è statadedicata una parte delle ore del tirocinio, sia per quanto riguarda il CRM di Infocertche le piattaforme di altri clienti. Tra le attività svolte è opportuno riportare:su Sugar per Infocert la sostituzione della schermata completa di composizione emailcon una semplificata con meno funzioni (già costruita in passato da una collega) el’aggiunta della possibilità di utilizzare modelli preimpostati;per Associazione Bancaria Italiana l’aggiunta dei meta-tag per la condivisione neisocial web (Facebook, Twitter e Linkedin) dei contenuti del sito di Bancaforte se-condo lo standard Open Graph, l’aggiornamento del player video da Adobe FlashPlayer ad HTML5 e la correzione di un bug che provocava una visualizzazione sba-gliata della slide dei contenuti correlati ad un articolo;Per Tecla (una azienda di business digitale) l’aggiunta su Sugar di un campo cherappresenta il valore iniziale di una opportunità commerciale, riempito in creazionee non più modificato (mentre il valore denominato ”probabile” può variare all’evol-versi dell’offerta). Ciononostante, il progetto può dirsi completato con successo: tutti i requisitisono stati rispettati e il progetto è stato terminato entro il limite delle 250 ore ditirocinio, che si sono suddivise all’incirca tra le seguenti attività: • 60 ore di apprendimento di metodologie e tecniche aziendali e studio del fun- zionamento di Sugar (sia tramite la documentazione ufficiale che quella azien- dale); • 10 ore per lo studio delle tecniche di information retrieval e delle possibili solu- zioni applicabili al problema; • 40 ore per la progettazione e l’implementazione della soluzione con la libreria PHP-ML; • 5 ore di studio delle basi di funzionamento della piattaforma Solr (tramite la documentazione ufficiale); • 80 ore per la progettazione e l’implementazione della soluzione con Solr; • 15 ore complessive per test e correzione di bug nella soluzione con Solr; • 40 ore complessive per l’implementazione delle modifiche sopra citate.Sfruttando le potenzialità di Solr è possibile ampliare il sistema sviluppato inte-grando una pagina di ricerca avanzata in tutta la knowledge base, senza utilizzarecomplesse query SQL su database. La ricerca per parola chiave, unita alla funzio-ne MoreLikeThis potrebbe essere il punto di partenza anche per una repository diticket, sotto forma di FAQ, consultabili dai clienti prima di inviare una richiesta diassistenza.

40 Capitolo 7. Conclusioni Questo progetto è stata la prima esperienza di progettazione di un sistema infor-matico che, seppur semplice, ha permesso di approcciarsi a problemi, progettazionie soluzioni di livello aziendale e non più prettamente accademico. L’esperienza siè conclusa con un bilancio assolutamente positivo, sia per quanto riguarda le com-petenze tecniche apprese che le soft skills trasversali: lavoro in team, organizzazionedel lavoro, rispetto dei tempi, comunicazione e cooperazione.

41 A Codice sorgente In questa appendice sono riportati i codici sorgente più rilevanti scritti durante l’im- plementazione del progetto. A.1 caricaSolr.php1 File caricaSolr.php2 <?php //ritorna true se l'inserimento ha avuto successo, false altrimenti3 function loadSolr($id_ticket) {4 if(is_null($id_ticket) || !is_string($id_ticket) || strlen($id_ticket)==0)5 return false;6 global $db;7 $q= \"SELECT name,description,resolution,parent_id,date_entered8 FROM mce_csdemands WHERE id='$id_ticket'\";9 $db_result_id = $db->query($q);10 if($row = $db->fetchByAssoc($db_result_id))) {11 $dettagli = [];12 $dettagli['name'] = $row['name'];13 $dettagli['id'] = $id_ticket;14 $dettagli['richiesta'] = preg_replace('/(===)(.*)(===)/', '',15 $row['description']);16 $dettagli['richiesta'] = str_replace(\"\n\", '',$dettagli['richiesta']);17 $dettagli['risposta'] = preg_replace('/(===)(.*)(===)/', '',18 $row['resolution']);19 $dettagli['risposta'] = str_replace(\"\n\", '',$dettagli['risposta']);20 $dettagli['parent_id'] = $row['parent_id'];21 $dateArr = date_parse_from_format(\"Y-m-d H:i:s\", $row['date_entered']);22 $dettagli['de_year']= $dateArr['year'];23 $dettagli['de_month']=$dateArr['month'];24 $dettagli['de_day']=$dateArr['day'];2526 //ottengo le categorie:27 $qCat = \"SELECT mce_checktreedoms.id AS mce_checktreedoms_id,28 mce_checktreedoms.parent_node FROM mce_csdemands29 INNER JOIN mce_csdemand_mce_checktreedom ON30 mce_csdemands.id=mce_csdemand_mce_checktreedom.record_id31 INNER JOIN mce_checktreedoms ON32 mce_csdemand_mce_checktreedom.checktreedom_id=mce_checktreedoms.id33 WHERE mce_csdemands.id='$id_ticket'\";34 $db_result_cat = $db->query($qCat);35 $elencoCat = [];36 while($rowCat = $db->fetchByAssoc($db_result_cat))37 array_push($elencoCat, [38 'id'=>$rowCat['mce_checktreedoms_id'],

42 Appendice A. Codice sorgente39 'parent_node'=>$rowCat['parent_node'],40 ]);41 //ottengo gli utenti che hanno contribuito:42 $qUt = \"SELECT assigned_user_id FROM mce_csdemands_wflow43 WHERE parent_id='$id_ticket'\";44 $db_result_users = $db->query($qUt);45 $elencoUtenti=[];46 while($rowUs = $db->fetchByAssoc($db_result_users))47 array_push($elencoUtenti, $rowUs['assigned_user_id']);48 $dettagli['assigned_users'] = $elencoUtenti;4950 //ottengo i gruppi degli utenti che hanno contribuito:51 $qSg = \"SELECT securitygroup_id FROM mce_csdemands_wflow52 WHERE parent_id='$id_ticket'\";53 $db_result_sg= $db->query($qSg);54 $elencoSg=[];55 while($rowSg = $db->fetchByAssoc($db_result_sg))56 array_push($elencoSg, $rowSg['securitygroup_id']);57 $dettagli['securitygroups'] = $elencoSg;5859 //ricreo la gerarchia delle categorie:60 foreach($elencoCat as $nodo)61 if($nodo['parent_node']=='') //categoria più generica62 $dettagli['id_cat1'] = $nodo['id'];63 foreach($elencoCat as $nodo)64 if (!is_null($dettagli['id_cat1']) &&65 !strcmp($nodo['parent_node'], $dettagli['id_cat1']))66 $dettagli['id_cat2'] = $nodo['id'];67 foreach($elencoCat as $nodo)68 if (!is_null($dettagli['id_cat2']) &&69 !strcmp($nodo['parent_node'], $dettagli['id_cat2']))70 $dettagli['id_cat3'] = $nodo['id']; //categoria più interna71 $dettagli = json_encode($dettagli);72 return caricaJsonSolr($dettagli); }737475 }7677 function caricaJsonSolr($dettagli) {78 global $sugar_config;79 $url = $sugar_config['solr_url'] . \"update/json/docs\";80 $ch = curl_init();81 curl_setopt($ch, CURLOPT_URL, $url);82 curl_setopt($ch, CURLOPT_HTTPHEADER, [\"Content-type: application/json\"]);83 curl_setopt($ch, CURLOPT_POST, true);84 curl_setopt($ch, CURLOPT_POSTFIELDS, $dettagli);85 curl_setopt($ch, CURLOPT_TIMEOUT, 10);86 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);87 $data = curl_exec($ch);88 $risposta = json_decode($data, true);89 if (curl_errno($ch)) {


Like this book? You can publish your book online for free in a few minutes!
Create your own flipbook