Facoltà di Ingegneria



Documenti analoghi
La memoria - generalità

Sistemi Operativi. 5 Gestione della memoria

Strutture di Memoria 1

Sistemi Operativi GESTIONE DELLA MEMORIA SECONDARIA. D. Talia - UNICAL. Sistemi Operativi 11.1

Sistemi Operativi. Memoria Secondaria GESTIONE DELLA MEMORIA SECONDARIA. Struttura del disco. Scheduling del disco. Gestione del disco

Sistemi Operativi IMPLEMENTAZIONE DEL FILE SYSTEM. D. Talia - UNICAL. Sistemi Operativi 9.1

Tipi classici di memoria. Obiettivo. Principi di localita. Gerarchia di memoria. Fornire illimitata memoria veloce. Static RAM. Problemi: Dynamic RAM

Sistemi Operativi 1. Mattia Monga. a.a. 2008/09. Dip. di Informatica e Comunicazione Università degli Studi di Milano, Italia mattia.monga@unimi.

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

Introduzione all Information Retrieval

Sistemi Operativi IMPLEMENTAZIONE DEL FILE SYSTEM. Implementazione del File System. Struttura del File System. Implementazione

Automazione Industriale (scheduling+mms) scheduling+mms.

Informatica 3. LEZIONE 21: Ricerca su liste e tecniche di hashing. Modulo 1: Algoritmi sequenziali e basati su liste Modulo 2: Hashing

Coordinazione Distribuita

9. Memoria Virtuale. 9. Memoria Virtuale. 9. Memoria Virtuale

Approccio stratificato

Testi di Esercizi e Quesiti 1

La memoria centrale (RAM)

Sistemi Operativi GESTIONE DELLA MEMORIA CENTRALE. D. Talia - UNICAL. Sistemi Operativi 6.1

Strutturazione logica dei dati: i file

GESTIONE DELLA MEMORIA CENTRALE

Memoria Virtuale. Anche la memoria principale ha una dimensione limitata. memoria principale (memoria fisica) memoria secondaria (memoria virtuale)

MODELLO CLIENT/SERVER. Gianluca Daino Dipartimento di Ingegneria dell Informazione Università degli Studi di Siena

Gestione della memoria centrale

Prova di Esame - Rete Internet (ing. Giovanni Neglia) Lunedì 24 Gennaio 2005, ore 15.00

Introduzione. Coordinazione Distribuita. Ordinamento degli eventi. Realizzazione di. Mutua Esclusione Distribuita (DME)

Basi di Dati Relazionali

Calcolatori Elettronici. La memoria gerarchica La memoria virtuale

e-dva - eni-depth Velocity Analysis

Scheduling della CPU. Sistemi multiprocessori e real time Metodi di valutazione Esempi: Solaris 2 Windows 2000 Linux

Materiali per il modulo 1 ECDL. Autore: M. Lanino

Architettura hardware

Corso di Informatica

A intervalli regolari ogni router manda la sua tabella a tutti i vicini, e riceve quelle dei vicini.

Database. Si ringrazia Marco Bertini per le slides

Architettura dei calcolatori II parte Memorie

Capitolo 11 La memoria cache

Calcolatori Elettronici A a.a. 2008/2009

Sistema operativo: Gestione della memoria

Un sistema operativo è un insieme di programmi che consentono ad un utente di

Gestione della memoria. Paginazione Segmentazione Segmentazione con paginazione

Valutazione delle Prestazioni. Valutazione delle Prestazioni. Architetture dei Calcolatori (Lettere. Tempo di risposta e throughput

Introduzione all analisi dei segnali digitali.

Corso di Informatica

La Videosorveglianza Criteri per il dimensionamento dello storage

Sistemi Operativi. Scheduling della CPU SCHEDULING DELLA CPU. Concetti di Base Criteri di Scheduling Algoritmi di Scheduling

Sistemi Operativi SCHEDULING DELLA CPU. Sistemi Operativi. D. Talia - UNICAL 5.1

Inizializzazione degli Host. BOOTP e DHCP

Guida Compilazione Piani di Studio on-line

Organizzazione della memoria

CORSO DI RETI SSIS. Lezione n.2. 2 Novembre 2005 Laura Ricci

Reti di Telecomunicazione Lezione 8

Gerarchie di memoria Divide et impera. Gerarchie di memoria La congettura 90/10. Gerarchie di memoria Schema concettuale

Architettura dei computer

MService La soluzione per ottimizzare le prestazioni dell impianto

Introduzione. Classificazione di Flynn... 2 Macchine a pipeline... 3 Macchine vettoriali e Array Processor... 4 Macchine MIMD... 6

I Thread. I Thread. I due processi dovrebbero lavorare sullo stesso testo

SISTEMI DI ELABORAZIONE DELLE INFORMAZIONI

IL RISPARMIO ENERGETICO E GLI AZIONAMENTI A VELOCITA VARIABILE L utilizzo dell inverter negli impianti frigoriferi.

ControlloCosti. Cubi OLAP. Controllo Costi Manuale Cubi

Con il termine Sistema operativo si fa riferimento all insieme dei moduli software di un sistema di elaborazione dati dedicati alla sua gestione.

Gestione della Memoria

ARCHITETTURA DI RETE FOLEGNANI ANDREA

Memoria Virtuale. Lezione 29 Sistemi Operativi

Creare una Rete Locale Lezione n. 1

Università degli Studi di Salerno

STRUTTURE DEI SISTEMI DI CALCOLO

Funzioni in C. Violetta Lonati

Network Monitoring. Introduzione all attività di Network Monitoring introduzione a Nagios come motore ideale

Indice generale. OOA Analisi Orientata agli Oggetti. Introduzione. Analisi

Laboratorio di Informatica

Scenario di Progettazione

Volume GESTFLORA. Gestione aziende agricole e floricole. Guidaall uso del software

Il sistema operativo TinyOS

TECNICHE DI SIMULAZIONE

Come leggere ed interpretare la letteratura scientifica e fornire al pubblico informazioni appropriate sui farmaci

Il database management system Access

Comunicazione tra Computer. Protocolli. Astrazione di Sottosistema di Comunicazione. Modello di un Sottosistema di Comunicazione

Università degli Studi di Padova Dipartimento di Matematica. - Corso di Laurea in Informatica

MODULO 5 Appunti ACCESS - Basi di dati

Software di sistema e software applicativo. I programmi che fanno funzionare il computer e quelli che gli permettono di svolgere attività specifiche

ARCHIVIAZIONE DOCUMENTALE NEiTdoc

Federico Laschi. Conclusioni

GESTIONE DELLE TECNOLOGIE AMBIENTALI PER SCARICHI INDUSTRIALI ED EMISSIONI NOCIVE LEZIONE 10. Angelo Bonomi

Quinto Homework. Indicare il tempo necessario all'esecuzione del programma in caso di avvio e ritiro fuori ordine.

Architettura di un sistema di calcolo

FONDAMENTI di INFORMATICA L. Mezzalira

Esercizio 1: trading on-line

I database relazionali (Access)

Organizzazione degli archivi

CORSO ACCESS PARTE II. Esistono diversi tipi di aiuto forniti con Access, generalmente accessibili tramite la barra dei menu (?)

Reti di Telecomunicazione Lezione 6

Esempio: aggiungere j

Introduzione alla Virtualizzazione

Prova di Esame - Rete Internet (ing. Giovanni Neglia) Lunedì 24 Gennaio 2005, ore 15.00

1- OBIETTIVI DEL DOCUMENTO 2- INTRODUZIONE

La gestione di un calcolatore. Sistemi Operativi primo modulo Introduzione. Sistema operativo (2) Sistema operativo (1)

Gestione della memoria

DMA Accesso Diretto alla Memoria

Transcript:

Facoltà di Ingegneria Tesi di Laurea Magistrale in Ingegneria Informatica APPLICAZIONE DI TECNICHE STREAMING AL QUERY CACHING Relatore Prof. Luca Becchetti Candidato Federico Magnifici Anno Accademico 2008/2009

Facoltà di Ingegneria Tesi di Laurea Magistrale in Ingegneria Informatica APPLICAZIONE DI TECNICHE STREAMING AL QUERY CACHING Relatore Prof. Luca Becchetti Candidato Federico Magnifici Anno Accademico 2008/2009

A mia madre

Indice 1 Introduzione 4 1.1 Descrizione del problema..................... 4 1.2 Lavoro svolto........................... 9 1.3 Risultati ottenuti......................... 11 1.4 Struttura della tesi........................ 12 2 Background 14 2.1 Cache: state of art........................ 14 2.1.1 Politiche di replacement................. 20 2.1.1.1 LFU - Least Frequently Used......... 21 2.1.1.2 LRU - Least Recently Used.......... 21 2.1.1.3 FIFO - First in - First out........... 22 2.1.1.4 Algoritmo di Belady.............. 22 2.2 Data Streaming Model...................... 22 2.2.1 Frequent Elements.................... 26 2.2.1.1 Algoritmi Counter-Based........... 28 2.2.1.2 Algoritmi Sketch-Based............ 30 3 Caching of Query Results 33 3.1 Algoritmi di Query Caching................... 36 3.1.1 Space-Saving Query Caching............... 37 3.1.2 Optimal-LFU Query Caching.............. 44 3.1.3 CountMin-Sketch Query Caching............ 48 2

Indice 3 3.1.4 FIFO Query Caching................... 52 3.1.5 LRU Query Caching................... 53 3.2 Result Query Caching...................... 54 3.2.1 Analisi Query Log.................... 55 3.3 Result Query Caching con Index Cache............. 60 3.3.1 Analisi URL Log..................... 65 4 Implementazione Java del Query Caching 69 4.1 Politche di Query Caching.................... 69 4.1.1 Implementazione Space-Saving Query Caching..... 70 4.1.2 Implementazione Optimal-LFU Query Caching..... 71 4.1.3 Implementazione CountMin-Sketch Query Caching.. 73 4.1.4 Implementazione FIFO Query Caching......... 74 4.1.5 Implementazione LRU Query Caching......... 74 4.2 Implementazione Index Cache.................. 75 5 Analisi sperimentale 78 5.1 Space-Saving Query Caching................... 79 5.2 Optimal-LFU Query Caching.................. 82 5.3 CountMin-Sketch Query Caching................ 83 5.4 FIFO Query Caching....................... 85 5.5 LRU Query Caching....................... 87 5.6 Confronto prestazionale degli algoritmi............. 88 6 Conclusioni 95 A JavaDoc 100

Capitolo 1 Introduzione Indice 1.1 Descrizione del problema.............. 4 1.2 Lavoro svolto..................... 9 1.3 Risultati ottenuti.................. 11 1.4 Struttura della tesi................. 12 1.1 Descrizione del problema Nell ultimo decennio, il web, a seguito di una forte e continua crescita è divenuto una delle applicazioni popolari più utilizzate. Quotidianamente milioni di pagine sono create per intrattenimento, lavoro, fornire servizi, ecc. Per cercare di ottenere le informazioni d interesse tra questa enorme quantità di dati, gli utenti sempre più spesso ricorrono all uso dei motori di ricerca a cui sottopongono query su un qualsiasi argomento ed in qualsiasi forma, infatti queste possono essere raggruppate in tre macro-categorie: Informazione (utenti che cercano informazioni di tipo generale su uno specifico argomento), Navigazione (utenti che cercano home page o web site su specifiche entità) e Transazionali. Il successo dei motori di ricerca sta nell effettuare in maniera efficiente e veloce il crawling e l indicizzazione del web, i quali consentono successiva- 4

1.1 Descrizione del problema 5 mente ricerche soddisfacenti per i milioni di utenti che ogni giorno ne fanno uso. Questo fa sì che il problema del Web Information Retrieval sia divenuto con il passare del tempo sempre più complicato per i motori di ricerca in quanto aumenta il volume dell informazione da indicizzare, che si traduce nella necessità di una maggiore quantità di memoria, oltre naturalmente a forti ripercussioni sui tempi di risposta. I sistemi di information retrieval distribuiti sono un semplice modo per progettare motori di ricerca che lavorano su grandi collezioni di dati, in particolare il sistema viene dispiegato su un cluster di server ognuno dei quali è responsabile di una partizione dell intero indice secondo una politica di bilanciamento del carico. Per migliorare ulteriormente le capacità di tale sistema viene utilizzato il processo di collection selection, ossia le query vengono schedulate e passate al server di maggiore competenza tramite l utilizzo di una funzione di selezione di tipo statistico come: la document frequency (numero di documenti contenenti il termine di query), la collection frequency (numero di occorrenze del termine di query nella collezione). In definitiva il motore di ricerca una volta ricevuta la query deve processare una grande quantità di dati e lo fa interrogando un indice distribuito, ordina i risultati in base al loro score e costruisce una pagina dei risultati contenente URLs con rispettivi titoli, snippets e link collegati. I sistemi di ricerca dell informazione distribuiti, come ad esempio i motori di ricerca, ricorrono all utilizzo del caching, eventualmente applicato anche su più livelli di memorizzazione, al fine di migliorare le prestazioni. Il caching consente infatti: di ridurre il tempo di risposta per l utente finale, di diminuire il carico complessivo nel sistema e di limitare la congestione della rete. Poiché nei sistemi distribuiti in generale, ed in particolare nei motori di ricerca, gli elementi in cache sono caricati da diversi server sparsi nella rete, il costo dei fallimenti in cache (cache misses), in termini di latenza, può essere notevole. Il fine delle politiche di caching è quello di ridurre tali costi. Ulteriore motivo nel progettare motori di ricerca con architettura distribuita, oltre alla scalabilità

1.1 Descrizione del problema 6 ed alla tolleranza ai guasti, è quello della scarsa disponibilità di risorse su un singolo server, in particolare la memoria ram necessaria a mantenere le cache entries. Fig. 1.1: Architettura di un web search engine distribuito La figura 1.1 mostra l architettura distribuita di un motore di ricerca, costituito da un insieme di server che eseguono moduli core, ognuno dei quali è responsabile di una parte dell intero indice invertito. Al di sopra di questi server di ricerca vi è un ulteriore host, chiamato broker, il quale schedula le queries ai vari server e colleziona i risultati restituiti, successivamente unisce ed ordina in base allo score i risultati ricevuti e compone un vettore di DocId per i top-k documents (ossia i primi k documenti con punteggio maggiore). Questi DocId vengono usati per recuperare dal Urls/Snippet Server le rispettive Urls e Snippet che verranno inserite nella pagina HTML restituita all utente. Il caching nei motori di ricerca può essere di tipo off-line (quindi statico) oppure on-line (dinamico), nel primo approccio il contenuto della cache è

1.1 Descrizione del problema 7 basato su informazioni storiche ed è periodicamente aggiornato, quello dinamico, invece, aggiorna la cache in accordo con lo stream di richieste, in particolare, al verificarsi di un cache miss viene individuata una entry attualmente in cache da rimpiazzare con il nuovo elemento secondo una particolare politica di replacement qualora la cache sia satura, altrimenti viene semplicemente inserita al suo interno. Le prestazioni di un sistema di caching sono influenzate oltre che dalla dimensione della cache (in generale maggiore è la sua dimensione e migliori sono le prestazioni in termini di hit-rate) anche dal principio di località temporale e spaziale, il quale si basa sull osservazione che: quando si fa riferimento ad un elemento per il principio spaziale vi è un alta probabilità che vengano richiesti entro breve tempo elementi che hanno un indirizzo vicino a quello corrente, mentre per quello temporale vi è un alta probabilità che si faccia riferimento entro breve tempo allo stesso elemento ed è sulla località che si basano la maggior parte delle politiche di replacement. La presenza di località nello stream di query sottomesse dagli utenti, consente una forte riduzione dei tempi di risposta del motore di ricerca, in quanto molte query possono essere risolte, completamente o parzialmente, direttamente dalla cache senza interrogare il motore di ricerca vero e proprio cioè senza accedere all indice invertito. Inoltre, nel caso si verifichi un Cache Miss, il tempo utilizzato per effettuare il look-up in cache di un elemento non presente viene considerato trascurabile rispetto al tempo necessario al search engine per risolvere la query, in quanto questo deve fare accesso all indice invertito che risiede su disco, recuperare le postings list, calcolarne l intersezione, classificare i risultati in base al proprio score, recuperare per ogni risultato: url, snippet e titolo, infine costruire una pagina html da ritornare all utente. A conferma della presenza e dell importanza di località nelle stream di queries vi è il lavoro [1] che analizza i query log di vari motori di ricerca per studiare l impatto della località nelle prestazioni dei sistemi di caching,

1.1 Descrizione del problema 8 ottenendo i seguenti risultati principali: la presenza di località è molto forte, in quanto il 30-40% delle queries sono ripetute seguendo una distribuzione di Zipf, le query con elevata frequenza di ripetizione sono condivise da differenti utenti e possono essere mantenute in cache. La maggior parte delle queries ripetute sono referenziate nuovamente entro un breve intervallo, c è comunque una porzione importante di queries condivise da utenti distinti che si ripetono ad intervalli di tempo più lunghi. Quindi se il caching deve essere effettuato lato utente, allora un periodo di qualche ora dovrebbe essere sufficiente a coprire la località temporale, mentre il caching lato server richiede periodi più lunghi, nell ordine di qualche giorno. Una delle possibili strategie di implementazione del caching in un motore di ricerca è chiamata caching of query results, questa tiene traccia della results list associata ad una data query, in particolare per ogni documento vengono mantenuti Url, titolo e snippet. Due sono gli aspetti cruciali da affrontare nella progettazione di tale strategia, il primo consiste nello stimare il numero di documenti che devono essere mantenuti in cache per ogni query visto che il motore di ricerca, ne ritorna, in genere qualche centinaia di migliaia. In soccorso vengono diversi studi, ed in particolare [2], il quale dimostra che circa l 86% degli utenti utilizza al più i prima trenta riferimenti ritornati, mentre circa il 70% degli utenti non va oltre i primi dieci e che il 90 % non va oltre i primi 50 riferimenti. Quindi, in funzione della dimensione della cache a disposizione, si mantengono un numero di risultati per ogni query che oscilla tra i primi 30 ed i 50 documenti. Il secondo aspetto, invece, consiste nella scelta della politica di replacement dei query results, ossia la politica per individuare quali query results dovranno essere eliminati dalla cache nel caso in cui un nuovo insieme di risultati debba essere mantenuto. Vi sono diverse politiche di replacement, illustrate nel capitolo 2, tra cui LFU, LRU, FIFO prese in considerazione e riadattate per il presente lavoro. In generale un parametro che viene utilizzato per individuare il candidato alla eliminazione è il così detto

1.2 Lavoro svolto 9 lifespan, cioè il il tempo che intercorre tra due accessi allo stesso elemento, quindi per il principio di località, per avere un migliore hit rate, l elemento in cache con il più grande lifespan è un buon candidato ad essere eliminato. Quando un utente effettua una query al motore di ricerca, quest ultimo verifica se in cache è mantenuta la corrispondente results list associata alla query, in caso affermativo (Cache Hit), questa viene restituita immediatamente all utente a basso costo, in quanto necessita solo di essere formattata e inviata, altrimenti, in caso negativo(cache Miss), la query viene processata normalmente dal motore di ricerca. 1.2 Lavoro svolto Il presente lavoro si propone di presentare, realizzare e valutare in termini prestazionali nuovi approcci implementativi per politiche di Query Caching basati su tecniche di streaming, al fine di migliorare le performance dei motori di ricerca in termini di Hit Rate e tempo medio di risposta, senza alterarne parametri di ranking e classificazione. In particolare, questi approcci di Query Caching vengono inquadrati in due scenari architetturali distinti, un primo scenario è il classico Result Query Caching in cui viene mantenuta la results list di ogni query che è in cache così che, all arrivo di una nuova query si verifica prima se la corrispondente lista dei risultati è in memoria cache, altrimenti la si processa normalmente tramite l accesso all indice invertito. Nel secondo scenario invece si utilizza prima una Index cache, ossia una cache a livello di indice invertito che restituisce le urls di interesse per ogni query senza dover accedere all indice, successivamente si utilizza sempre una Result Query Caching ma questa volta tenendo traccia solamente della singola url con i corrispondenti titolo e snippet e non dell intera query con associata la result list. Le motivazioni principali di questo scenario architetturale, che richiede un ulteriore livello di cache, sono la possibilità di riuscire ad ottenere in alcuni casi la corrispondente results list di una query che ad

1.2 Lavoro svolto 10 esempio non è mai stata osservata fino a quel momento o che comunque non è direttamente mantenuta in cache, come composizione di urls appartenenti alle queries precedenti e che attualmente sono in cache secondo una delle politiche di caching implementate. In entrambi gli scenari presi in considerazione, quello che si vuole andare a realizzare è un approccio di caching dinamico ossia algoritmi in grado di prendere decisioni online in funzione dello stream di elementi osservati (che in questo caso sono le queries in uno scenario e le urls associate alle varie queries nel secondo scenario) come ad esempio quale elemento rimuovere dalla cache per far spazio ad uno nuovo, le così dette politiche di replacement. Oltre alla progettazione e valutazione di politiche di caching conosciute quali FIFO (First in-first out) o LRU (least recently used), l aspetto innovativo di questo lavoro è la realizzazione di politiche di caching LFU (Least Frequenty Used) utilizzando tecniche algoritmiche di data streaming. In tale scenario vengono proposti, con relativa implementazione e analisi, due approcci di caching basati su modelli di data streaming al fine di realizzare politiche di replacement del tipo LFU, ossia quelle politiche che allo scopo di sfruttare la località temporale e spaziale presente all interno di una sequenza di elementi, nello specifico queries o urls, individuano ed eliminano gli elementi dalla cache in base alla loro frequenza. Al fine di realizzare efficienti politiche di gestione della cache basate sulla frequenza degli elementi, vengono utilizzate tecniche di streaming che permettono di mantenere, mediante compatte strutture dati (o sketch) una stima degli elementi la cui frequenza eccede una data soglia. Più in particolare, vengono considerati: un algoritmo basato sull utilizzo di una struttura sketch [3] e chiamato Count Min Sketch un algoritmo basato sullo Space Saving per la stima delle frequenze, presentato in [4]

1.3 Risultati ottenuti 11 Sempre nell ambito delle politiche LFU viene proposto anche un algoritmo che realizza una versione ottima del concetto di politica LFU stessa dove vengono calcolate le frequenze esatte di tutti gli elementi nello stream. I primi due approcci elencati sono di tipo approssimato, quindi differiscono completamente da quello che realizza un LFU ottimo, in quanto non tentano di calcolare la frequenza esatta degli elementi, ma ne calcolano una stima con l obiettivo di limitarne al minimo l errore introdotto ed accettando così una certa perdita di accuratezza rispetto a quello ottimo, ma ottenendo maggiore efficienza in termini di tempo di esecuzione e soprattutto di spazio necessario per le strutture dati utilizzate. Per entrambi gli approcci approssimati viene fatta l assunzione di un modello di streaming denominato cash register, cioè un modello dove sono consentiti solamente incrementi delle frequenze stimate e mai decrementi, cosa che nell astrazione generale di uno streaming model non è necessariamente corretta. 1.3 Risultati ottenuti I principali risultati ottenuti a seguito di una dettagliata analisi sperimentale condotta sulle varie tecniche di Dynamic Query Caching proposte (capitolo 3), sono mostrati nel capitolo 5. Di particolare interesse sono le prestazioni raggiunte dallo Space-Saving Query Caching sia in termini di Hit Rate, che in termini di Execution Time necessario al processamento dell intero input, viene mostrato come tale algoritmo utilizzando cache di dimensioni modeste rispetto alla lunghezza dell input consente di evitare al motore di ricerca il processamento attraverso indice invertito di circa il 47% delle queries nell appraccio Results Query Caching classico e di circa il 55% delle urls in quello con Index Cache. Prestazioni decisamente peggiori sono ottenute dall altro algoritmo basato su tecniche di streaming, cioè il CountMin-Sketch Query Caching. Classiche tecniche di caching quali FIFO o LRU raggiungono per il determinato file di log utilizzato, prestazioni elevate e relativamente simili a quelle dello Space-Saving Query Caching in termini di Hit Rate, ma peggiori

1.4 Struttura della tesi 12 dal punto di vista del tempo necessario all algoritmo per il processamento dell input. Infine per lo scenario Result Query Caching con Index Cache, cioè lo scenario orientato alle urls, le varie tecniche algoritmiche proposte garantiscono un Query Hit Rate del tutto simile a quello raggiunto dalle stesse in un classico approccio di Result Query Caching orientato alla gestione delle queries. 1.4 Struttura della tesi Capitolo 2 vengono illustrate le motivazioni che hanno portato all introduzione del concetto di caching a partire dai sistemi operativi fino ad arrivare al web, successivamente vengono presentate le principali politiche di replacement utilizzate per la gestione della cache, ed infine viene illustrato il data streaming model, i suoi scenari di riferimento con particolare attenzione a quanto concerne il problema dei Frequent Elements e le principali tecniche algoritmiche utilizzate. Capitolo 3 vengono presentate in dettaglio le tecniche di Query Caching proposte con relative strutture dati. Queste sono classificate in tre macro-categorie: LFU, FIFO, LRU, mettendone in risalto differenze, vantaggi e svantaggi di ognuna. Successivamente vengono illustrati gli scenari di Query Caching utilizzati, in particolare quello del Result Query Caching e quello del Result Query Caching con Index Cache. Per entrambi gli scenari viene fornita un analisi del file di Query Log utilizzato come input per le simulazioni condotte Capitolo 4 vengono presentati i principali aspetti implementativi degli algoritmi di Query Caching proposti in ambiente Java SE 6.0 Capitolo 5 vengono illustrati e motivati i risultati dell analisi sperimentale condotta sui vari algoritmi al fine di ricavarne vari indici prestazionali

1.4 Struttura della tesi 13 come Hit Rate o Tempo di Esecuzione al variare della dimensione della cache utilizzata. Capitolo 6 vengono presentate le considerazioni finali a conclusione del lavoro svolto in materia di Query Caching, considerando scenari distinti ed avendo utilizzato principalmente sia sofisticate tecniche di Data Streaming sia classiche politiche di caching puro. Appendice A vengono fornite le JavaDoc dei vari metodi Java realizzati per implementare i cinque algoritmi di Dynamic Query Caching proposti.

Capitolo 2 Background Indice 2.1 Cache: state of art.................. 14 2.1.1 Politiche di replacement............... 20 2.2 Data Streaming Model............... 22 2.2.1 Frequent Elements.................. 26 2.1 Cache: state of art La memoria di una qualsiasi unità di elaborazione è strutturata in maniera gerarchica in modo da ottimizzare al meglio i parametri di progettazione per un sistema di memorizzazione quali: costo, capacità e tempo di accesso. La figura 2.1 mostra una generica struttura gerarchica della memoria in cui vengono utilizzati più livelli di memorizzazione, ciascuno di diversa velocità e dimensione, realizzati con tecnologie diverse al fine di ottenere un trade-off tra costo e prestazioni. Si può osservare come livelli di memoria adiacenti all unita di processamento o CPU hanno una capacità minore rispetto a quelli più in basso nella gerarchia, ma tempi di accesso molto inferiori, così come si osserva che minore è il tempo di accesso e maggiore è il costo di tale memoria. Un sistema di memoria gerarchico può essere reso efficiente se la modalità di accesso ai dati ha caratteristiche prevedibili ed è su questo che si 14

2.1 Cache: state of art 15 Fig. 2.1: Struttura gerarchica della memoria basa il principio di località, ossia sul fatto che in un dato istante i riferimenti alla memoria interessano solamente una porzione relativamente piccola dello spazio di indirizzamento. Le principali località d interesse per la progettazione di un sistema di memoria gerarchico sono: Località Temporale: quando si fa riferimento ad un elemento di memoria, c è la tendenza a far riferimento allo stesso elemento entro breve (si pensi al riutilizzo di istruzioni e dati all interno di cicli). Località Spaziale: quando si fa riferimento ad un elemento di memoria, c è la tendenza a far riferimento entro breve tempo ad altri elementi che hanno un indirizzo vicino a quello dell elemento corrente (si pensi all accesso sequenziale a dati organizzati a vettori o matrici) La cache, che in figura 2.1 rappresenta lo strato più alto (livello 1), ha una capacità ridotta, un costo più elevato, ma tempi di accesso inferiori rispetto

2.1 Cache: state of art 16 ai livelli sottostanti, che senza perdere generalità nel seguito verranno intesi come un unico blocco e chiamati memoria principale, in particolare la cache è una memoria temporanea in cui sono contenuti una collezione dei dati più utilizzati (duplicati degli originali mantenuti in memoria principale), i quali possono essere recuperati in maniera rapida quando richiesti. Caratteristica di tale sistema di memorizzazione è che non si ha nessuna certezza che il dato richiesto sia presente all interno della cache, quindi è sempre conveniente verificarne la presenza prima di accedere alla memoria principale, questo perché in caso di Cache Hit, ossia il dato è presente in cache, il tempo risparmiato nel recuperare il dato rispetto a caricarlo dalla memoria principale o secondaria, dove è contenuta la versione originale, è molto grande. Il funzionamento generale è mostrato in figura 2.2 per quanto riguarda un Cache Hit, mentre in figura 2.3 è rappresentato il funzionamento di un Cache Miss. Fig. 2.2: CACHE HIT La memoria principale può essere qualcosa di semplice come un disco rigido, ma anche un complesso database distribuito, come ad esempio il DNS

2.1 Cache: state of art 17 Fig. 2.3: CACHE MISS o il web. In entrambi i casi, la memoria principale può essere modificata senza passare dalla cache, il che comporta problemi di coerenza tra i dati originali e quelli nella cache. In alcuni casi è possibile validare i dati contenuti nella cache interrogando la memoria principale per verificare se questi sono ancora attuali. Tale lavoro è quello che fanno i server proxy: chiedono al server HTTP se la pagina che mantengono è stata modificata dopo la sua memorizzazione. In altri casi, si utilizza un meccanismo di scadenza a tempo dei dati memorizzati e fino a quando un dato presente nella cache non è scaduto questo viene utilizzato, anche se non corrisponde a quanto presente nella memoria principale. Questo è il meccanismo adottato dal DNS. Una cache riduce il carico di richieste che dovrebbe essere smaltito dalla memoria principale e dal collegamento tra questa e l utilizzatore dei dati, migliorando le prestazioni del sistema. Si pensi per esempio ad un server proxy utilizzato da molti utenti: quando un utente richiede una pagina che è

2.1 Cache: state of art 18 già stata richiesta da un altro in precedenza, il proxy potrà rispondere senza doversi collegare al sito originale, ed eviterà così di caricare sia il sito originale che la rete, migliorando così le prestazioni del sistema anche per le richieste che devono essere inoltrate ai siti originali. In alcuni casi la memoria cache supporta anche la modifica dei dati. Questo risultata essere semplice da implementare se la cache è l unico percorso di accesso alla memoria principale, come nel caso della cache della memoria RAM presente nei processori: la cache accetta una operazione di scrittura verso la RAM (permettendo al processore di proseguire l elaborazione), presenta da subito i dati aggiornati al processore se questo ne chiede nuovamente la lettura, e si prende carico di scriverli sulla RAM prima di eliminare la pagina. In questo modo, se un dato in memoria è modificato frequentemente dal processore, è possibile mantenere le modifiche nella cache ed evitare continui trasferimenti verso la RAM. Esistono vari tipi di cache che si distinguono tra loro in base al contesto in cui vengono utilizzate, in particolare: CPU CACHE che mantiene copie dei dati ai quali si fa più frequentemente accesso in memoria principale. Si tratta di una piccola e veloce memoria installata direttamente sul processore o nelle sue immediate vicinanze. Viene utilizzata memoria di tipo SRAM, grazie al suo ridotto consumo e alla notevole velocità. DISK CACHE consiste nell avere un hard disk che ha al suo interno una parte di RAM, dove possono venire caricati i settori del disco logicamente contigui a quello richiesto. Quando si accede in lettura al disco, nel caso i dati richiesti siano presenti nella cache si evita lo spostamento della testina di lettura del disco stesso, velocizzando il reperimento dell informazione e contribuendo a ridurre l usura del disco stesso. PAGE CACHE consiste nell avere una parte della RAM usata dal sistema operativo in cui si copiano dall hard disk i dati correntemente

2.1 Cache: state of art 19 in uso. In questo caso, l accesso alla RAM è più veloce dell accesso al disco. Poiché la memoria disponibile è generalmente limitata, il sistema operativo cerca di mantenere il più possibile in memoria una pagina, mantenendo una tabella delle pagine che non sono usate correntemente ma lo sono state in passato. Quando occorre caricare una pagina nuova sarà sovrascritta la più vecchia non ancora in uso. DNS CACHE è un server DNS che non possiede informazioni autoritative, ma è in grado di chiederle ai server autoritativi e memorizzarne le risposte. I server DNS utilizzati dagli utenti di Internet sono normalmente dei server cache. Il DNS usa un meccanismo di scadenza, per cui ogni record recuperato da un server autoritativo è valido per un certo tempo, dopo il quale deve essere scartato. WEB CACHE è una parte di hard disk dedicata da un server proxy http, oppure dal browser di un utente, a salvare documenti web (pagine HTML, immagini, etc.) il quale permette una riduzione dell uso della banda e il tempo di accesso ad un Sito web. Una web cache memorizza copie di documenti richiesti dagli utenti, successive richieste possono essere soddisfatte dalla cache se si presentano certe condizioni. Le Web cache di solito raggiungono picchi d efficienza nell ordine del 30%-50%, e migliorano la loro efficienza al crescere del numero di utenti. Naturalmente è necessaria la gestione della coerenza tra i dati che sono in cache e quelli nel sistema remoto. Le Web cache si differenziano in: lato client e lato server. Le cache lato client, anche chiamate forward cache, vengono utilizzate per servire un gruppo locale di utenti. Le cache lato server, anche conosciute come reverse-caches e web accelerator, sono poste davanti ai server per ridurre il loro carico di lavoro. Inoltre esistono servizi detti Content Delivery Network, costituiti da una rete di server dislocati in punti strategici di internet, che erogano contenuti di siti molto frequentati.

2.1 Cache: state of art 20 2.1.1 Politiche di replacement Quando un dato è richiesto alla memoria principale dalla CPU e la cache risulta essere satura è allora necessario che quest ultima liberi una entry per poter memorizzare il nuovo dato, per far ciò possono essere utilizzate diverse euristiche o politiche di replacement che consentono l individuazione del dato da rimpiazzare. Il problema fondamentale di ogni politica di replacement è quello di dover predire il dato della cache che verrà richiesto nel futuro con minor probabilità. Predire il futuro è difficile, soprattutto per le cache hardware che devono sfruttare regole facilmente implementabili in circuiteria, a tale scopo esistono una serie di politiche, tuttavia nessuna di esse può essere ritenuta perfetta. La scelta dell algoritmo di replacement ha un profondo impatto sulle performance della cache in termini di miss rate e quindi indirettamente sulla dimensione della cache. L obiettivo della ricerca in tale settore è quello di provare ad ottenere algoritmi di replacement che possano garantire elevate prestazioni a cache di piccole dimensioni. La bontà di tali algoritmi risiede nella loro capacità di rimuovere quei dati di cui si presume non si abbia bisogno nell immediato e quindi non è necessario tenerli in cache e mantenere quelli che hanno maggiori probabilità di essere acceduti, ad esempio perchè più frequenti o perchè più recenti. Per fare ciò è indispensabile il monitoraggio di tutte le entry della cache che porta l algoritmo a stabilire un trade off tra le prestazioni desiderate in termini di hit rate e l overhead computazionale necessario per le operazioni di monitoraggio e replacement. I principali algoritmi di replacement, che verranno presentati nelle seguenti sottosezioni, sono: LFU = Least Frequently Used LRU = Least Recently Used FIFO = First In-First Out

2.1 Cache: state of art 21 2.1.1.1 LFU - Least Frequently Used Questo algoritmo utilizza la storia degli accessi ai dati mantenuti in cache allo scopo di predire la probabilità di un successivo accesso al dato. In particolare viene mantenuto un contatore di accessi per ogni elemento in cache e quando si rende necessaria una eliminazione di uno di essi per fare posto ad uno nuovo, viene scelto ed eliminato l elemento con il valore del contatore più basso, ossia l elemento meno frequente tra quelli mantenuti in cache. Sfortunatamente questo tipo di approccio soffre di un problema particolare che consiste nella possibilità di avere elementi con un contatore delle occorrenze molto elevato e quindi fortemente radicati all interno della cache. Questi elementi che potrebbero non essere più acceduti nuovamente andrebbero eliminati il prima possibile, ma ciò non è reso possibile in quanto possiedono un valore del contatore maggiore rispetto ad altri elementi, che pur essendo acceduti frequentemente vengono eliminati avendo un valore del contatore inferiore. Questo porta ad un fenomeno chiamato cache pollution (inquinamento della cache), ossia la presenza dei suddetti elementi inattivi all interno della cache provoca un aumento del miss rate e quindi un degrado delle prestazioni della cache. In generale, una politica di invecchiamento viene utilizzata per attenuare l effetto del cache pollution incrementando così le prestazioni dell algoritmo LFU, questa consiste nel decrementare progressivamente i contatori degli elementi inattivi rendendoli quanto prima possibili candidati per l eliminazione. 2.1.1.2 LRU - Least Recently Used L algoritmo LRU è una delle tecniche di replacement più popolari, soprattutto in applicazioni commerciali. Questa politica utilizza il principio di località temporale ed elimina quell elemento in cache che è stato referenziato meno di recente nel passato ed assume che non venga nuovamente referenziato nel prossimo futuro.

2.2 Data Streaming Model 22 Questa strategia è semplice da implementare per piccole dimensioni della cache, ma diventa computazionalmente costosa per quelle di dimensioni più grandi. Inoltre LRU, nella decisione di quale elemento eliminare, tiene conto solamente del lasso di tempo trascorso dall ultimo accesso all elemento e non della frequenza, ossia del numero di volte che quell elemento è stato referenziato. Una possibile implementazione dell algoritmo LRU consiste nell utilizzare degli age bits per ogni entry della cache, in questo modo si tiene traccia della entry referenziata meno di recente, in quanto ogni volta che una entry viene acceduta, vengono modificati gli age bits di tutte le altre entry. 2.1.1.3 FIFO - First in - First out L algoritmo FIFO (First In First Out) rimpiazza la entry con l elemento inserito da più tempo. Si noti che l algoritmo LRU e FIFO non operano in maniera analoga, in quanto LRU rimpiazza le celle utilizzate meno recentemente (indipendentemente da quando i rispettivi elementi siano stati inseriti in cache), mentre FIFO rimpiazza le celle che sono da più tempo in cache (indipendentemente da quanto esse siano state utilizzate). 2.1.1.4 Algoritmo di Belady È considerato come l algoritmo di replacement ottimale, sostanzialmente rimpiazza la entry della cache il cui elemento non sarà referenziato per più tempo in futuro. Naturalmente l assunzione del prevedere quale siano le entry accedute in futuro rende questo algoritmo impossibile da realizzare in pratica. 2.2 Data Streaming Model Il Data Streaming è definito come l arrivo in ordine casuale di un flusso (stream) continuo di dati al sistema di calcolo (o unità di processamento) che può leggerli solo una volta, prima che questi vengano distrutti (o archiviati

2.2 Data Streaming Model 23 in un sistema in cui la rilettura risulta troppo costosa). Il processamento, che consiste nel calcolo di determinate funzioni sullo stream di dati deve avvenire online, ossia al tempo di osservazione, ricorrendo a particolari strutture dati, inoltre data la natura generalmente complicata e non risolubile in maniera esatta e deterministica di tali funzioni senza il salvataggio dell intero input, vengono utilizzati algoritmi randomizzati o approssimati. Alcuni dei campi in cui si possono trovare problemi su Data Stream sono: applicazioni finanziarie, monitoraggio di reti, sicurezza, applicazioni web, reti di sensori ed in generale nelle reti di telecomunicazioni. Esempi specifici del Data Stream sono: Dato un link di comunicazione, calcolare il numero di pacchetti TCP/IP SYN senza il corrispondente pacchetto di ACK. Questa informazione può essere utilizzata per scovare attacchi denial-of-service. Calcolare quanti indirizzi IP distinti vengono inviati quotidianamente lungo una data connessione. Per stimare il carico di lavoro è sufficiente considerare un link da 2GB/s e pacchetti da 50 byte ciascuno. Quindi su tale link viaggiano 5 milioni di pacchetti al secondo, supponendo di essere interessati a tenere traccia dell indirizzo IP sorgente e destinazione del pacchetto per un totale di circa 10 byte, allora sarebbero necessari 50 MB di memoria al secondo per un totale di circa 4,5 TB al giorno. Una soluzione esatta richiederebbe l allocazione dell intero input, l alternativa è utilizzare algoritmi approssimati, i quali necessitano di un numero di bit logaritmico nella lunghezza dello stream. Riconoscere navigatori web tendenzialmente favorevoli a cliccare su link pubblicitari In generale, il modello di Data Streaming viene definito mediante un vettore a di dimensione n, il cui stato all istante t viene espresso come a(t) = [a 1 (t),...,a i (t),...,a n (t)]. Inizialmente a è un vettore con tutte le entry

2.2 Data Streaming Model 24 settate a zero, cioè a i (0)=0 i. Gli aggiornamenti del vettore, a seguito dell arrivo dei dati, sono rappresentati mediante un stream di coppie U=(i,c), dove i è un indice del vettore mentre c è un qualsiasi valore d incremento. In particolare il j-esimo update è definito come (i j, c j ) e consiste nell eseguire le seguenti operazioni: a i (j) = a i (j 1) + c j (2.1) a t (j) = a t (j 1) t i (2.2) In figura 2.4 viene mostrato un tipico scenario di data streaming composto da un unità di processamento ed uno stream di dati, ognuno dei quali corrispondente ad una coppia U j. Fig. 2.4: Streaming Model Si possono distinguere principalmente tre modelli di Data Stream, che si differenziano tra essi per i vincoli sugli elementi dello stream: CASH REGISTER MODEL in cui sono consentiti solamente aggiornamenti che incrementano di una quantità positiva le entry del vettore a e non vi sono vincoli sull ordine con cui vengono ricevuti tali aggiornamenti. In particolare, per il generico aggiornamento U i =(i,c i ) vale che c i 0, con c i =1 caso d utilizzo molto diffuso nelle applicazioni di data stream.

2.2 Data Streaming Model 25 TURNSTILE MODEL in cui non vi sono vincoli né sull ordine con cui vengono compiuti gli aggiornamenti né sui possibili valori di c i. TIME SERIES MODEL in cui viene assunto l utilizzo di un vettore di lunghezza pari a quella dello stream, quindi ogni locazione a i viene aggiornata una sola volta, precisamente quando l elemento e i viene osservato. Questo modello è adatto a quei problemi in cui lo stream rappresenta l evolversi temporale di un segnale, ad esempio il numero di pacchetti IP che transitano nell unità di tempo in una connessione. Gli algoritmi per risolvere problemi su Data Stream vengono valutati rispetto alle seguenti metriche: Tempo di processamento di un update, espresso in termini di numero di operazioni necessarie per aggiornare la struttura dati in seguito all arrivo di un nuovo dato dallo stream, deve essere il minimo possibile. Spazio usato dall algoritmo, deve anch esso essere il minimo possibile, al più poli-logaritmico in n, (O(poly(log(n)))), ossia lo spazio necessario a rappresentare esplicitamente il vettore a. Accuratezza dell algoritmo approssimato, in generale è specificata tramite un coppia di parametri specificati dall utente, ɛ e δ, il cui significato è che l errore dell algoritmo in risposta ad una query è entro un limite ɛ con probabilità δ. Naturalmente lo spazio ed il tempo di processamento necessari all algoritmo dipendono dai parametri di accuratezza. Ad ogni istante t vari tipi di funzioni, generalmente con soluzione approssimata, possono essere calcolate sul vettore a(t), le più note sono: POINT QUERY denotato con ϱ(i), ritorna una stima del valore di a i RANGE QUERY ϱ(l, r) ritorna un approssimazione di r i=1 a i

2.2 Data Streaming Model 26 φheavy HITTERS ritorna quegli elementi la cui molteplicità eccede la frazione φ della cardinalità totale, cioè gli elementi tali che a i φ a 1 dove a 1 = n i=1 a i(t). In ogni sequenza di elementi è possibile trovare un numero di Heavy Hitters tra 0 e 1, viene approssimato considerando Heavy Hitters anche quegli elementi tali φ che a i (φ ɛ) a 1 per alcuni valori ɛ < φ. TOP-K ELEMENTS ritorna i K elementi più frequenti all interno dello stream. Infine, un ulteriore problema che riguarda il data streaming è quello dei Frequent Elements presentato in [5], che consiste nell individuare gli elementi più frequenti all interno di un flusso continuo (stream). Pur essendo il problema dei Frequent Elements simile a quello dei TOP-K Elements, i due presentano sostanziali differenze, infatti i Frequent Elements sono tutti gli elementi la cui frequenza eccede una data frazione della dimensione totale dello stream (φn), mentre i top-k elements sono esattamente i k elementi più frequenti. La soluzione esatta di questi problemi richiede la conoscenza completa della frequenza di tutti gli elementi, che è irrealizzabile per applicazioni con input di grandi dimensioni, per questo sono state versioni rilassate del problema originale. 2.2.1 Frequent Elements Il problema dei Frequent Elements è uno dei più studiati nel campo del Data Streaming a causa del suo vastissimo utilizzo in molte delle applicazioni il cui obiettivo è quello di processare flussi di elementi. Definito informalmente come: data una sequenza o flusso di elementi, il problema è semplicemente quello di trovare quegli elementi che occorrono più frequentemente, in generale, può essere formalizzato come individuare tutti gli elementi la cui frequenza sia maggiore di una specifica frazione del numero totale di elementi.

2.2 Data Streaming Model 27 Quest astrazione del problema dei Frequent Elements racchiude una grande varietà di scenari, come ad esempio quello in cui gli elementi osservati potrebbero essere i pacchetti che viaggiano sulla rete e quindi gli elementi frequenti potrebbero essere le destinazioni più popolari o gli utenti che utilizzano più banda; altro caso potrebbe essere quello in cui gli elementi dello stream sono le queries sottoposte ad un motore di ricerca ed individuare quelle più frequenti potrebbe essere utile per la gestione del caching (scopo del presente lavoro ed illustrato in dettaglio nel capitolo 3). Data la grande dimensione dell input e l elevata velocità con cui questo viene generato, si rende necessario utilizzare algoritmi in grado di elaborare ogni aggiornamento molto rapidamente, questo può essere facilitato utilizzando uno spazio di lavoro ridotto, ossia strutture dati piccole che consentano di accrescere il throughput. Ottenere soluzioni efficienti e scalabili per il problema dei Frequent Elements è anche importante in quanto molte applicazioni di streaming necessitano di individuare gli elementi frequenti come subroutine di una computazione più complessa, come ad esempio la gestione del query caching nei motori di ricerca. Il problema viene formalizzato come: dato uno stream S di elementi n elementi, e 1...e n, la frequenza di un elemento i è data da f i = {j e j = i}.gli φ-exact-frequent-elements sono l insieme degli elementi tali che: {i f i > φn}. Poiché il problema di individuare quali siano esattamente gli elementi frequenti all interno di uno stream è complesso in generale da risolvere, una valida alternativa può essere quella di considerare una versione approssimata del problema, la quale introduce una certa tolleranza sull errore ɛ compiuto nel calcolo degli elementi frequenti, formalmente: dato uno stream S di n elementi, il problema degli ɛ-approximate-frequent.elements consiste nell individuare l insieme F di elementi tale che:

2.2 Data Streaming Model 28 { i F, f i > (φ ɛ)n} Gli algoritmi per il problema dei Frequent Elements possono essere classificati principalmente in due categorie :Counter-Based e Sketch-Based. 2.2.1.1 Algoritmi Counter-Based In questa tipologia di algoritmi viene mantenuto un contatore per ogni elemento nell insieme di quelli monitorati, il quale rappresenta un piccolo sottoinsieme della totalità degli elementi osservati. Il contatore di un elemento monitorato e i, viene aggiornato ogni volta che l elemento e i è osservato nello stream, invece nel caso in cui l elemento osservato non è presente tra quelli monitorati, cioè non vi è nessun contatore associato, allora l algoritmo deve prendere una decisione circa scartare l elemento oppure sostituirlo ad uno di quelli monitorati. Alcuni degli algoritmi Counter-Based più conosciuti sono: Frequent il quale mantiene k contatori per monitorare k elementi, quando un nuovo elemento viene osservato, se questo è uno tra gli elementi monitorati allora il rispettivo contatore è incrementato, altrimenti vengono decrementati tutti i contatori. Nel caso in cui, un qualsiasi contatore raggiunga il valore 0, allora questo viene assegnato al prossimo elemento osservato. Inoltre, utilizza una particolare struttura dati la quale permette di effettuare il decremento di tutti i contatori con O(1) operazioni. In figura 2.5 è mostrato lo pseudo-codice dell algoritmo Frequent, dove T è l insieme degli elementi monitorati e c i è il contatore associato all i-esimo elemento in T. Space Saving di Metwally et al.[4] offre una soluzione integrata per il problema dei Frequent Elements e per quello dei top-k elements. Il funzionamento dell algoritmo è semplice, nello specifico: se un elemento monitorato viene osservato di nuovo allora il corrispondete contatore viene incrementato. Se invece l elemento osservato, e, non è tra quelli

2.2 Data Streaming Model 29 Fig. 2.5: Frequent Algorithm monitorati, si concede ad esso il beneficio del dubbio inserendolo al posto dell elemento min il cui contatore ha il minimo valore stimato. Al nuovo elemento e inserito viene assegnato un valore di contatore pari a quello del min + 1 nonostante potrebbe avere un valore compreso tra 1 e min + 1, questo perché l algoritmo è progettato per sbagliare solamente dal lato positivo in modo da non perdere mai un elemento frequente. In figura 2.6 è mostrato il funzionamento in pseudo-codice dello Space Saving. Per ogni elemento monitorato e i, l algoritmo mantiene traccia anche della sovrastima, ɛ i, risultante dall inizializzazione del suo contatore quando viene inserito nella lista di quelli monitorati e la sovrastima ɛ i viene settata al valore del contatore dell elemento rimpiazzato. La struttura dati utilizzata è chiamata Stream-Summary, la quale garantisce incrementi dei contatori senza violarne l ordine e tempi costanti per il recupero degli elementi. Tramite tale struttura dati, lo Space Saving riesce ad ottenere gli elementi frequenti all interno dello stream di lunghezza n con errore ɛ, utilizzando m = min( A, 1) ɛ contatori nel caso di una generica distribuzione degli elementi in input, questo garantisce che ogni elemento e i con frequenza f i > (φn) è si-

2.2 Data Streaming Model 30 Fig. 2.6: Space Saving Algorithm curamente ritornato. Se invece gli elementi nello stream seguono una distribuzione skewed (distribuzione di Zipf), ossia pochi elementi hanno una frequenza molto elevata mentre tanti elementi (quasi la totalità) hanno un frequenza bassa, allora l algoritmo può utilizzare solamente m = min( A, ( 1) 1 α, 1 ) contatori per mantenere i Frequent Elements con ɛ ɛ errore ɛ, dove α è il parametro di Zipf. 2.2.1.2 Algoritmi Sketch-Based Gli algoritmi Sketch non monitorano un sottoinsieme di elementi ma forniscono, con minore accuratezza, una stima della frequenza per tutti gli elementi dello stream, utilizzando una matrice C di contatori. In particolare, ogni elemento osservato viene mappato sullo spazio dei contatori tramite un insieme di funzioni hash h 1...h d scelte a caso tra un famiglia di funzioni pairwise-indipendent ed i rispettivi contatori dell elemento, individuati come detto tramite funzioni hash, vengono incrementati. Naturalmente, a causa delle collisioni delle funzioni hash si ha una perdita dell accuratezza nel calcolo dei Frequent Elements. La principale tecnica Sketch-Based è il CountMin-Sketch [3], il quale utilizza una matrice di contatori di dimensione

2.2 Data Streaming Model 31 d x w. I valori di d e w vengono ottenuti in funzione dei parametri (ɛ, δ) forniti dall utente, come mostrato nell equazioni (2.3) w = exp ɛ d = ln 1 δ (2.3) Il numero di funzioni hash necessarie all algoritmo è pari al numero di righe d della matrice, questo perché ripetere d volte la stima di un elemento riduce esponenzialmente la probabilità di errore. Inoltre il valore del contatore associato al generico elemento e i è stimato come: fi = min j C[j, h j (i)], l utilizzo di una funzione min è dovuto al fatto che eventuali collisioni delle funzioni hash possono provocare esclusivamente una sovrastima della frequenza degli elementi e mai sottostime, quindi prendere il valore minimo significa minimizzare il possibile errore introdotto. Infine l utilizzo di una funzione min garantisce che f i abbia un errore al più pari a ɛn con probabilità almeno di (1 δ). Conseguentemente, l algoritmo utilizza spazio nell ordine di O( 1 log 1) e tempo nell ordine di O(log 1 ). In figura 2.7 è illustrato lo ɛ δ δ pseudo-codice per l aggiornamento dell algoritmo CountMin-Sketch. Fig. 2.7: CountMin-Sketch Algorithm In conclusione, le tecniche Sketch-Based consentono di monitorare tutti gli elementi presenti nello stream e non un sottoinsieme come per le Counter- Based, quindi forniscono una stima delle frequenze di tutti gli elementi osservati, anche se risultano essere meno sensibili all ordine con cui gli elementi nello stream arrivano. Tuttavia queste tecniche sono più costose dal punto di

2.2 Data Streaming Model 32 vista computazionale, in quanto per ogni elemento osservato è necessario l aggiornamento di più contatori, infine è bene notare che non offrono garanzie circa l errore introdotto nello stimare le frequenze degli elementi e questo fa sì che siano utilizzabili solo per un numero limitato di tipi di queries.

Capitolo 3 Caching of Query Results Indice 3.1 Algoritmi di Query Caching............ 36 3.1.1 Space-Saving Query Caching............ 37 3.1.2 Optimal-LFU Query Caching............ 44 3.1.3 CountMin-Sketch Query Caching.......... 48 3.1.4 FIFO Query Caching................. 52 3.1.5 LRU Query Caching................. 53 3.2 Result Query Caching................ 54 3.2.1 Analisi Query Log.................. 55 3.3 Result Query Caching con Index Cache..... 60 3.3.1 Analisi URL Log................... 65 Gli obiettivi principali del presente lavoro sono di proporre e valutare in termini prestazionali alcune nuove tecniche di Dynamic Query Caching per motori di ricerca basate o su tecniche streaming o su classiche politiche di caching generico. In particolare tali politiche vengono inquadrate in due distinti scenari di Query Caching, denominati Result Query Caching e Result Query Caching con Index Cache. Il Result Query Caching gestisce una memoria cache contenente queries con le rispettive results list in funzione di determinate proprietà (come frequenza o tempo di osservazione) - quindi si è nel classico scenario in cui 33

34 il motore di ricerca osserva ed analizza online (tramite tecniche di streaming) un flusso di queries proveniente dagli utenti del web-. Il Results Query Caching con Index Cache invece utilizza una struttura ausiliaria che nello specifico corrisponde ad una cache a livello di indice, la quale restituisce le urls di risposta per ogni query, quindi viene realizzato sempre un Result Query Caching, questa volta però osservando uno stream di urls indipendenti tra loro, ma derivanti dalle stesse queries utilizzate nel caso precedente. La motivazione per cui si è scelto di sviluppare un sistema di caching dinamico in cui le entry della cache sono gestite tramite politiche di replacement, e non un caching statico, dove le entry contengono le queries più popolari le quali vengono aggiornate periodicamente, è che non c è nessuna certezza sul fatto che queries popolari in un dato intervallo temporale lo siano anche nel successivo intervallo. Inoltre un sistema dinamico consente di catturare meglio il concetto di query più recente indipendentemente dalla sua popolarità, questo può avere un impatto positivo sulle prestazioni dei motori di ricerca attuali, in quanto la popolarità delle queries varia troppo rapidamente per poter essere catturata staticamente. Il primo step consiste nell analizzare il file di Query Log, che nel primo scenario è costituito dalla sequenza delle queries sottoposte in ordine temporale al motore di ricerca, mentre nel caso dell Index Cache è il log delle urls ottenute dalle rispettive queries ordinate temporalmente nel medesimo file di log. Il fine di tale analisi è quello di evidenziare e quantificare la presenza di località nella sequenza di queries che il motore di ricerca riceve e che rappresenta la principale ragione di un utilizzo efficiente del caching. In particolare, il principio di località per la progettazione di un sistema di caching nei motori di ricerca si suddivide in: principio di località temporale: ossia il tempo medio che intercorre nella ripetizione della stessa query. Una forte località temporale fa sì che una query si ripeta abbastanza spesso nella sequenza e quindi mantenerla in cache consente di ottenere un elevato HIT-RATE.

35 principio di località spaziale: che nel contesto del web caching è considerata come il numero di ripetizioni di una query all interno di una piccola finestra temporale. Per questo tipo di esperimento, il file di Query Log utilizzato è un sottoinsieme di quello fornito da AOL [6] del 2006, costituito da circa 20 milioni di queries; per la simulazione svolta vengono prese in considerazione le prime 3 milioni di queries corrispondenti ad una settimana di interrogazioni ad AOL Search Engine, in particolare le queries sottoposte tra il 01/03/2006 ed il 07/03/2006. Dopo l analisi del Query Log si è proceduto alla progettazione degli algoritmi di Query Caching, alcuni di essi basati sul modello di streaming, mentre altri sui classici approcci di caching generici quali FIFO o LRU. Tali tecniche risultano valide sia per lo scenario chiamato Result Query Caching sia per quello denominato Result Query Caching con Index Cache e che verranno presentati in dettaglio nella sezione 3.1. In particolare vengono proposti cinque distinti algoritmi per la risoluzione del problema del Query Caching nei motori di ricerca: un algoritmo di caching basato sullo Space-Saving (tecnica di streaming del tipo counter-based per il calcolo dei Frequent Elements e dei TOP-K Elements) un algoritmo di caching basato sul CountMin-Sketch (tecnica di streaming del tipo sketch-based per il calcolo di varie funzioni tra cui quella dei Frequent Elements) un algoritmo di caching basato sul modello LFU ottimo, ossia sul conteggio esatto delle occorrenze di tutti gli elementi nello stream un algoritmo di caching basato su una politica FIFO un algoritmo di caching basato su una politica LRU

3.1 Algoritmi di Query Caching 36 Infine nel capitolo 5 viene fornita un analisi prestazionale in funzione delle metriche d interesse, quali Hit-Rate e Tempo di esecuzione, dei vari algoritmi proposti, evidenziandone pro e contro di ognuno. Allo scopo di ottenere i risultati dei vari algoritmi su cui effettuare l analisi prestazionale, sono state effettuate delle simulazioni considerando dimensioni crescenti della dimensione della cache e mantenendo solamente i primi tre documenti più rilevanti per ogni query. 3.1 Algoritmi di Query Caching Lo scopo del presente paragrafo è quello di presentare cinque tecniche per la gestione del Dynamic Query Caching di cui due basate su modelli di data streaming e le restanti tre su classiche politiche di caching quali, FI- FO, LRU, LFU. In particolare viene illustrato in dettaglio il principio generale di funzionamento per tutti gli algoritmi proposti e di cui verrà fornita successivamente anche un analisi prestazionale teorica. In seguito invece, precisamente nella sezione 4.1, verranno presentati gli aspetti implementativi dei vari algoritmi proposti e le rispettive strutture dati in ambiente JAVA per entrambi gli scenari di Dynamic Query Caching considerati, cioè il classico Results Query Caching (3.2) ed il Result Query Caching con Index Cache (3.3). Le politiche di Dynamic Query Caching proposte nel presente lavoro vengono classificate secondo tre macro-categorie: Least Frequently Used (LFU) descritta in 2.1.1.1 Fifo (First in - First out) descritta in 2.1.1.3 Least Recently Used (LRU) descritta in 2.1.1.2 Nell ambito delle politiche LFU, ossia quelle politiche basate sul concetto di frequenza delle queries osservate, vengono proposti tre algoritmi di Dynamic Query Caching, di cui due ottenuti da innovative tecniche di Data

3.1 Algoritmi di Query Caching 37 Streaming. In particolare, il modello di Data Streaming preso in considerazione è quello Cash Register, ossia dove non c è nessun vincolo sull ordine degli elementi nello stream e dove sono consentiti solamente incrementi delle quantità mantenute, in questo caso le frequenze delle queries (urls). In particolare: Space-Saving Query Caching Optimal-LFU Query Caching CountMin-Sketch Query Caching I restanti due algoritmi invece sono basati rispettivamente su strategie del tipo FIFO (First in - First out) e LRU (Least Recently Used), cioè sul concetto di query meno recente. FIFO Query Caching LRU Query Caching Una premessa alla presentazione delle varie tecniche di Query Caching consiste nel precisare che il lavoro si basa sull assunzione che ogni elemento dello stream (query o url) con le rispettive informazioni aggiuntive, quali Results List, Snippet, Titolo, ecc. occupa all interno della cache una singola locazione di memoria indipendentemente dalla lunghezza dello stesso. Questa assunzione viene resa fattibile e accettabile in quanto nelle varie strutture dati utilizzate verranno memorizzati i valori hash delle queries (urls) i quali hanno generalmente sempre dimensione (in byte) uguali, e non gli elementi veri e propri, i quali potrebbero richiedere una quantità di spazio non indifferente. 3.1.1 Space-Saving Query Caching Come esposto in 2.2.1.1, lo Space Saving è una innovativa tecnica di Data Streaming del tipo Counter-Based per il calcolo approssimato degli elementi più frequenti (o anche TOP-k elements) all interno di uno stream di dati.

3.1 Algoritmi di Query Caching 38 Questa tecnica può essere riadattata con le dovute modifiche al problema del Dynamic Query Caching, consentendo così il calcolo online delle frequenze delle queries o urls, a seconda dello scenario considerato, più frequenti per la gestione della cache in ottica LFU. In generale, il principio di funzionamento dell algoritmo è molto semplice: quando una query (in alternativa, a seconda dello scenario, può essere una url) e i viene ricevuta dal motore di ricerca, questo in primis verifica se tale query (url) sia già contenuta in cache. In caso la query sia contenuta in cache, allora viene recuperata la corrispondente results list eventualmente interrogando un server secondario per ottenere informazioni aggiuntive tipo Snippet, Titolo, Riferimenti,ecc. ed in maniera contestuale a tale operazione viene aggiornato il contatore count i delle occorrenze associato a tale query (url). Invece, nel caso in cui la query (url) non sia momentaneamente presente in cache, questa viene inserita al posto della query (url) che risulta avere la minima frequenza stimata (cioè con il min(count j )) ed il corrispondente contatore viene settato al valore del min(count j ) +1. Inoltre una sovrastima ɛ i è mantenuta per ogni query (url) che viene inserita in cache, questa misura viene settata al valore del contatore della query (url) rimpiazzata e rappresenta una sovrastima dell inizializzazione del contatore. La dimensione della cache utilizzata, ossia il numero di locazioni di memoria che la costituiscono, assumendo che ogni coppia (query, contatore) (in alternativa (url, contatore)) occupi una singola locazione indipendentemente dalla lunghezza della stessa coppia, è data dal numero di contatori che l algoritmo utilizza per stimare le frequenze delle queries (urls). Il numero m di contatori necessario è ottenuto in funzione dell errore ε tollerato nella stima delle frequenze, in particolare, avendo assunto una distribuzione uniforme delle queries (urls) presenti nel file di log, si ha che: m = 1 ε (3.1) quindi, si può dedurre che minore è l errore ε e maggiore è l accuratezza

3.1 Algoritmi di Query Caching 39 nella stima delle frequenze, tuttavia questo richiede un numero maggiore di contatori, cioè una quantità di spazio maggiore è necessaria all algoritmo. L architettura della memoria cache utilizzata dallo Space Saving è costituita fondamentalmente da due blocchi, un primo blocco corrispondente ad una tavola hash ed un secondo blocco corrispondente ad una struttura dati più complessa e sofisticata, denominata Stream-Summary. La figura 3.1 mostra la struttura logica della cache nell algoritmo Space Saving. Fig. 3.1: Strutture Cache nello Space-Saving Prima di illustrare in dettaglio entrambe le strutture costituenti una memoria cache e spiegare le motivazioni che hanno portato al loro utilizzo, può risultare comodo dare l intuizione che vi è dietro una tale architettura. Molto semplicemente, la tavola hash svolge il ruolo di cache vero e proprio, ossia è la struttura dati che viene interrogata ad esempio dal motore di ricerca, per verificare la presenza o meno di una data query o url con tempi di look-up costanti. In caso la query (url) sia presente in cache viene restituita all utente direttamente la corrispondente results list contenuta nella tavola hash senza dover processare la query (url), quindi con notevole risparmio di tempo. Altrimenti, nel caso in cui la query (url) non fosse presente, si procederebbe con il normale processamento della stessa tramite indice invertito. La seconda delle strutture dati invece, è una struttura dati ordinata e viene utilizzata per mantenere il conteggio delle frequenze (stimato) che l algoritmo calcola per le varie query (url) osservate nello stream. Cominciamo con la Stream-Summary, questa consente l incremento dei

3.1 Algoritmi di Query Caching 40 contatori senza violarne l ordine e garantisce un tempo costante per il recupero dell informazione al suo interno. In tale struttura dati, tutte le queries (urls) con lo stesso valore di contatore (cioè stesso numero di occorrenze) sono mantenute in una una lista collegata. Ogni elemento della lista contiene quindi un oggetto formato dalla query (url) e i e dal valore della sovrastima ɛ i per la frequenza della query (url) stessa. Questa lista collegata è mantenuta da un Bucket padre il quale contiene anche il valore comune del contatore delle queries (urls) nella lista. Tutti i Bucket della struttura dati sono collegati tra loro mediante una doppia lista ordinata per valore del contatore, in modo da avere una struttura dati ordinata. Inizialmente tutti gli m oggetti (query (url), sovrastima) sono vuoti e collegati ad un singolo Bucket padre settato al valore zero, come mostrato nello schema generico di figura 3.2. Fig. 3.2: Stream-Summary stato iniziale Quando un contatore count i associato ad un determinata query (url) viene aggiornato, si cerca il Bucket più vicino con valore maggiore del Bucket attuale della query (url), se tale Bucket esiste ed ha un valore uguale al nuovo valore del contatore della query (url), allora questa viene eliminata dalla lista delle queries (urls) del vecchio Bucket per essere inserita in quella del Bucket nuovo. Se invece tale Bucket non esiste, allora un nuovo Bucket viene creato con il valore aggiornato della query (url) e questa viene eliminata dal vecchio Bucket per essere inserita come unico elemento nella lista di quello appena creato. Naturalmente, essendo i Bucket mantenuti in una lista ordi-

3.1 Algoritmi di Query Caching 41 nata, quello appena creato deve essere inserito nella giusta posizione in modo da non violarne l ordine - questo rende possibile una scansione sequenziale della struttura-. Infine, nel caso in cui il vecchio Bucket abbia una lista delle queries (urls) vuota, viene eliminato dalla struttura. Per comprendere meglio il funzionamento dell algoritmo e della Stream- Summary, si consideri il seguente semplice esempio in cui vengono utilizzati due contatori, quindi m=2, ed uno stream composto dalle seguenti queries (urls) S = X, Y, Y, Z. In figura 3.3 viene mostrata la struttura dati dopo aver osservato S =X, Y. Fig. 3.3: Stream-Summary dopo S=X,Y Al terzo step invece, cioè dopo aver osservato S =X, Y, Y, viene creato un nuovo Bucket con valore 2, come illustrato figura 3.4. Fig. 3.4: Stream-Summary dopo S=X,Y,Y Infine, all arrivo di un nuovo elemento (query o url) Z, il quale non è ancora presente nella struttura dati e considerato il fatto che non sono disponibili

3.1 Algoritmi di Query Caching 42 ulteriori contatori da assegnare a tale query (url), si procede con il rimpiazzo della query q j (url) con contatore minimo, in questo caso X, si settano il contatore al valore min j +1 e la sovrastima ɛ z = min j per la nuova query (url) (la figura 3.5 mostra lo scenario appena descritto). Fig. 3.5: Stream-Summary dopo S=X,Y,Y,Z Le queries (urls nel secondo scenario) contenute nella Stream Summary, vengono mantenute, come già detto, anche in una tavola hash in modo da garantire un costo ammortizzato costante (Θ(1)) per l accesso ad una query (url) senza dover necessariamente scorrere sequenzialmente l intera Stream- Summary. La figura 3.6 illustra il funzionamento della tavola hash ogni volta che una nuova query (url) viene osservata nello stream, tramite tale struttura è possibile verificarne la presenza effettuando un look-up in tempo costante. In caso l elemento desiderato non fosse in cache, cioè il look-up sulla tavola hash avesse esito negativo, allora si procede con il normale processamento della query da parte del motore di ricerca e si rimpiazza quella attualmente in cache con contatore minore (grazie alla struttura ordinata Stream Summary). In caso positivo, invece, è intuibile quale sia il beneficio di poter restituire direttamente la results list all utente, cioè l enorme riduzione del tempo di attesa e di processamento. Come è facile notare, tale algoritmo simula alla perfezione una classica politica di caching LFU, ossia una politica di rimpiazzo degli elementi, che nel caso specifico corrispondono a queries o urls, in funzione della frequenza

3.1 Algoritmi di Query Caching 43 Fig. 3.6: Space Saving degli stessi. La novità introdotta dallo Space-Saving Query Caching sta nel fatto che le frequenze vengono stimate e non calcolate con esattezza, cercando di garantire il minimo errore possibile, in quanto il calcolo esatto per ogni elemento dello stream richiederebbe spazio e tempo computazionale troppo grande. L algoritmo garantisce che gli elementi frequenti ricevano un valore del contatore grande, quindi difficilmente verranno influenzati dagli elementi meno frequenti e cioè difficilmente verranno eliminati dall insieme degli elementi monitorati. Invece gli elementi meno frequenti, che risiederanno probabilmente nella parte bassa della struttura, ossia dove i valori dei contatori sono minori, saranno maggiormente soggetti ad essere rimpiazzati dai nuovi elementi osservati nello stream, introducendo così una maggiore possibilità di errore la quale si traduce in una diminuzione dell accuratezza. Indipendentemente dal tipo di distribuzione che gli elementi nello stream seguono, è facile osservare come l errore introdotto nella stima delle frequenze è inversamente proporzionale al numero di contatori utilizzati e cioè alla dimensione della cache utilizzata. Un simile comportamento verrà motivato in dettaglio dall analisi sperimentale condotta sull algoritmo e mostrata nella sezione 5.1.

3.1 Algoritmi di Query Caching 44 3.1.2 Optimal-LFU Query Caching Il secondo algoritmo di Query Caching proposto è basato completamente su una classica politica LFU ottima, ossia una politica in cui si mantiene il conteggio delle occorrenze esatto di tutti gli elementi osservati. Quindi ogni volta che si rende necessario un replacement all interno della cache sicuramente verrà eliminato l elemento che ha la minima frequenza senza il rischio di possibili errori dovuti all utilizzo delle frequenze stimate e non esatte. A differenza dello Space-Saving Query Caching (3.1.1), il quale basa le proprie decisioni di replacement in funzione delle frequenze stimate delle queries (urls), risolvendo così una versione rilassata del problema dei Frequent Elements, lo Optimal-LFU Query Caching prende decisioni di replacement in base al numero esatto di occorrenze delle queries (urls). Per fare ciò l algoritmo necessita di un contatore delle occorrenze per ogni singolo elemento distinto osservato nello stream. Si può facilmente intuire come questa tecnica sia di difficile, se non addirittura impossibile, applicazione in scenari reali in cui i motori di ricerca ricevono e processano diversi milioni di queries al giorno e quindi richiederebbe un tempo e soprattutto uno spazio computazionale troppo grande. Tuttavia, essendo in un contesto di simulazione relativamente piccolo (tre milioni di queries), si è deciso di implementare ugualmente una tale tecnica in quanto risulta essere un buon termine di paragone per le prestazioni degli algoritmi approssimati. Nello Optimal-LFU Query Caching la memoria cache è realizzata mediante un heap minimale ed in aggiunta a tale heap viene utilizzata una struttura dati ausiliaria, nello specifico una tavola hash, la quale mantiene traccia di tutte le queries (urls) distinte osservate con il rispettivo contatore delle occorrenze. L heap minimale rappresenta la cache vera e propria, ossia è la struttura dati che contiene le queries (urls) momentaneamente in cache. In figura 3.7 viene mostrate la struttura logica architetturale della cache utilizzata dallo Optimal-LFU Query Caching.

3.1 Algoritmi di Query Caching 45 Fig. 3.7: Optimal-LFU Query Caching L heap minimale è una particolare struttura dati rappresentante un albero binario quasi completo in cui ogni nodo diverso dalla radice soddisfa la seguente proprietà: il valore memorizzato in parent(i) è minore o uguale a quello memorizzato nel nodo i. In maniera equivalente può essere descritta come una struttura dati la quale garantisce che: il nodo radice contiene l elemento con il minimo valore del contatore delle occorrenze il valore dei contatori presenti all interno dei vari nodi cresce muovendosi dalla radice verso le foglie lungo qualsiasi cammino Le operazioni d interesse in tale struttura sono quelle di inserimento ed estrazione del minimo elemento. In particolare, per mantenere l albero quasi completo si inserisce il nuovo elemento (query o url con le rispettive informazioni aggiuntive, quali results list nel primo caso e snippet, titolo, ecc. nel secondo caso) come foglia posta a destra dell ultima foglia, cioè l albero viene completato per livelli. La nuova foglia viene poi sistemata nella posizione corretta del cammino che porta dalla sua posizione al nodo radice. L estrazione del minimo corrisponde alla rimozione della radice dell heap. Questa operazione viene realizzata eliminando l ultima foglia inserita e salvandone chiave e valore in radice, successivamente vengono ripristinate le

3.1 Algoritmi di Query Caching 46 proprietà precedentemente elencate per rispettare la condizione di min-heap. In figura 3.8 è mostrato un generico heap minimale in cui il nodo radice contiene l elemento e i con il minimo contatore ed ogni altro nodo nella gerarchia contiene elementi il cui valore risulta essere maggiore rispetto al predecessore ma inferiore al successore. Inoltre nel caso specifico dello Optimal-LFU Query Caching, l heap minimale che opera da cache viene ordinato in funzione delle frequenze degli elementi osservati ed ogni nodo contiene al proprio interno oltre il numero dell occorrenze (valore del contatore) come già detto, anche le relative informazioni associate alla query o url, tipo results list per le queries e snippet, titolo, ecc. per le urls. Fig. 3.8: Heap-Min Si può notare come utilizzare una simile struttura dati, quale l heap minimale, per implementare una memoria cache consenta di mantenere gli elementi (queries o urls) ordinati in funzione della frequenza, in modo tale da poter eliminare, ogni qual volta si renda necessario un replacement al suo interno, l elemento con il minimo numero di occorrenze corrispondente al nodo radice dell heap e realizzando così una politica di replacement LFU. Quindi ogni volta che una query o url è osservata nello stream, viene verificato tramite tavola hash se questa è già stata tracciata in precedenza o se

3.1 Algoritmi di Query Caching 47 invece viene vista per la prima volta. Nel caso in cui la tavola hash mantenga già un contatore per quella query (url) allora si effettua l aggiornamento dello stesso e successivamente si verifica se la cache, ossia l heap minimale, contenga già la query (url) in questione. Se tale condizione è verificata, quindi si ha un Cache Hit, allora viene restituita direttamente la results list mantenuta al suo interno senza dover processare la query (url) e contestualmente viene aggiornato il contatore della stessa. Se invece l elemento (query o url che sia) viene osservato per la prima volta, quindi non è presente nella tavola hash e necessariamente risulta essere un Cache Miss, si procede prima con il suo inserimento con contatore settato ad uno nella tavola e successivamente viene inserito in cache al posto dell elemento che risulta avere il minimo valore di occorrenze, cioè l elemento mantenuto come radice nell heap. Naturalmente tutto ciò avviene dopo che il motore di ricerca ha processato l elemento tramite l utilizzo dell indice invertito. Si procede in maniera analoga quando l elemento, pur essendo presente nella tavola hash, non lo è però all interno della cache e quindi si ha ugualmente un Cache Miss, allora il motore di ricerca deve comunque processare l elemento e successivamente viene effettuato sia l aggiornamento del corrispondente contatore nella tavola hash, sia l inserimento dell elemento stesso, con rispettivo contatore e results list, in cache al posto dell elemento che attualmente possiede il minimo valore della frequenza, che naturalmente corrisponde al nodo radice della struttura. Infine, come mostrato dall analisi sperimentale condotta nel capitolo per entrambi gli scenari di Query Caching considerati, si può osservare come avere un conteggio esatto delle frequenze degli elementi (con notevole incremento dell overhead computazionale) non implica necessariamente un miglioramento delle prestazioni dei sistemi di caching.

3.1 Algoritmi di Query Caching 48 3.1.3 CountMin-Sketch Query Caching L ultima tecnica di Query Caching della famiglia LFU che viene presentata è il CountMin-Sketch Query Caching. Questo algoritmo è basato su una particolare tecnica di Data Streaming denominata Count-Min Sketch di Cormode & Muthukrishnan [3]. A differenza dei precedenti due algoritmi presentati, tale tecnica di streaming è del tipo Sketch-Based, ossia utilizza una matrice di contatori per stimare la frequenza di tutti gli elementi osservati, quindi si distingue dallo Space-Saving in quanto quest ultimo stima la frequenza per un sottoinsieme di elementi e dal Model Streaming che calcola la frequenza esatta di ogni elemento nello stream. Il CountMin-Sketch Query Caching, come detto in precedenza, è una rielaborazione del conosciuto Count-Min Sketch per i problemi di data streaming. Questo algoritmo di caching implementa una memoria cache mediate un heap minimale come per il caso dello Streaming-Model Query Caching 3.1.2. Quindi il principio di funzionamento della cache è lo stesso, in cui si mantengono gli elementi (queries o url) in ordine crescente di frequenza nei nodi dell albero binario a partire della radice. Praticamente nella radice sarà sempre mantenuto l elemento in cache con il minimo valore del contatore delle occorrenze, quindi ogni volta che una decisione di replacement deve essere presa viene eliminato l elemento contenuto nel nodo radice per fare spazio a quello nuovo da inserire. Il concetto innovativo introdotto da tale algoritmo è l utilizzo di una sofisticata struttura dati oltre all heap minimale, il quale costituisce la cache vera e propria. Questa seconda struttura dati, chiamata CM-Sketch, non è altro che una matrice di contatori C[i,j] definita dai parametri (ɛ, δ) i quali rappresentano rispettivamente l errore tollerato e la probabilità limite con cui questo è garantito. Le dimensioni di tale matrice (d,w) sono ottenute in

3.1 Algoritmi di Query Caching 49 funzione dei parametri (ɛ, δ) come: exp w = d = ln 1 (3.2) ɛ δ In figura 3.9 viene mostrata una generica matrice di contatori di dimensione (d,w) utilizzata in una struttura dati CM-Sketch. Fig. 3.9: Matrice di contatori In realtà il CM-Sketch oltre ad una matrice di contatori utilizza anche un insieme di funzioni hash scelte tra una famiglia di funzioni pairwiseindipendent, precisamente sono necessarie d funzioni h 1, h 2...h d, una per ogni riga della matrice. Queste d funzioni hash hanno il compito di mappare ogni elemento osservato nello stream in una specifica cella della matrice, cioè su uno specifico contatore per ogni riga della matrice, h 1, h 2...h d : 1...n 1...w. Inizialmente ogni entry della matrice è settata a zero. Lo scopo dell utilizzo di questa particolare struttura dati denominata CM- Sketch è quello di stimare la frequenza di ogni elemento (query o url) nello stream. L operazione d interesse sul CM-Sketch in uno scenario di caching è quella di aggiornamento dei contatori: ogni volta che viene osservato un elemento si procede con l aggiornamento dei rispettivi contatori determinati dalle d funzioni hash calcolate sull elemento stesso. Formalmente, quando deve essere effettuato un aggiornamento (e t, c t ), dove e t è l elemento osservato e c t è la quantità che deve essere aggiunta (nel

3.1 Algoritmi di Query Caching 50 caso dei contatori delle queries o urls abbiamo c t =1) ad ogni contatore, si realizza la seguente operazione: 1 j d : count[j, h j (i t )] + c t (3.3) Si può notare come una simile tecnica di Data Streaming rientri nel generico modello CASH REGISTER, dove sono consentiti esclusivamente incrementi sui contatori della matrice. La figura 3.10 mostra quanto appena descritto sul funzionamento della struttura dati CM-Sketch. Fig. 3.10: CM-Sketch La frequenza stimata di un dato elemento e i è ottenuta mediante la funzione: fi = min j C[j, h j (i)], inoltre il teorema in [3] garantisce che per tale stima delle frequenze degli elementi nello stream valgono le seguenti relazioni: f i f i dove f i rappresenta la frequenza esatta dell elemento f i f i + ɛ a 1 con almeno probabilità 1 δ, dove a 1 = n i=1 a i(t) Il motivo per cui viene utilizzata una funzione min è fornito dal teorema stesso, in quanto avendo assicurato il fatto che f i f i, allora necessariamente la stima potrebbe approssimare la frequenza per eccesso e mai per difetto, prenderne il min significa minimizzare il possibile errore commesso nello stimare la frequenza dell elemento.

3.1 Algoritmi di Query Caching 51 In definitiva, riassumendo il funzionamento del CountMin-Sketch Query Caching, quando un elemento (query o url) viene osservato nello stream di dati, per prima cosa si procede con l aggiornamento dei rispettivi d contatori nella matrice C, successivamente si calcola f i dell elemento ed infine viene verificato se nella cache, cioè nell heap minimale, è già presente tale elemento. Se l elemento è presente, allora viene aggiornato il campo contatore del nodo contenente l elemento in questione e viene restituita all utente direttamente la results list senza dover processare la query. Viceversa, nel caso in cui invece l elemento non fosse presente nell heap minimale allora il motore di ricerca deve necessariamente processarlo e successivamente effettuare un replacement andando ad eliminare l elemento contenuto nel nodo radice della struttura e quindi corrispondente all elemento con la minima frequenza tra quelli in cache (politica LFU ) per fare spazio a quello appena processato. La figura 3.11 riassume il funzionamento del CountMin-Sketch Query Caching appena descitto. Fig. 3.11: CountMin-Sketch Query Caching

3.1 Algoritmi di Query Caching 52 3.1.4 FIFO Query Caching Il FIFO Query Caching è la più semplice strategia di Query Caching tra quelle proposte, questa si basa sulla politica di replacement del tipo FIFO, ossia il primo elemento che entra in cache è anche il primo ad uscire quando necessario, pertanto, contrariamente a quanto visto fino ad ora, non si utilizza più il concetto di frequenza degli elementi dello stream, ma semplicemente l ordine di arrivo in cache. L algoritmo utilizza una cache implementata tramite una semplice coda (FIFO), ogni volta che un elemento (query o url) viene osservato nello stream si controlla se tale elemento sia presente all interno della cache. Nel caso in cui tale condizione sia verificata (Cache Hit), allora viene recuperata la entry della coda contenente l elemento desiderato e si restituisce direttamente la corrispondente results list all utente. Nel caso invece in cui l elemento non sia presente nella coda (Cache Miss), allora il motore di ricerca deve necessariamente per prima cosa processare l elemento tramite un interrogazione all indice invertito, successivamente deve aggiornare la cache applicando un replacement al suo interno, che nel caso in questione corrisponde ad eliminare il primo elemento inserito in cache (cioè l elemento in testa alla struttura) per fare spazio al nuovo elemento che viene inserito in coda. In figura 3.12 viene sintetizzato il principio di funzionamento del FIFO Query Caching. Fig. 3.12: FIFO Query Caching

3.1 Algoritmi di Query Caching 53 3.1.5 LRU Query Caching L ultimo degli algoritmi proposti è l LRU Query Caching, come è facilmente deducibile dal nome, è una tecnica di caching basata su politiche LRU, ossia Least-Recently-Used. Sostanzialmente questa tecnica di caching prende decisioni di replacement degli elementi (query o url) contenuti in cache, in funzione della temporalità degli stessi, in pratica quando si rende necessario eliminare un elemento dalla cache per fare posto ad un altro appena osservato, si elimina quello referenziato meno di recente o comunque inutilizzato da più tempo. Anche in questa tecnica di Query Caching viene strutturata la cache mediante una coda, come per il FIFO Query Caching (3.1.4), ma le due tecniche che possono sembrare simili presentano sostanziali differenze. Mentre nel precedente FIFO Query Caching vengono rimpiazzati gli elementi che risiedono da più tempo in cache (indipendentemente da quanto essi siano stati referenziati), nell LRU Query Caching invece vengono rimpiazzati gli elementi utilizzati meno recentemente, indipendentemente da quando siano stati inseriti in cache. Il principio di funzionamento dell algoritmo è molto semplice: quando un elemento (query o url) viene osservato nello stream, si verifica prima se questo è presente già in cache ed in caso positivo viene prima recuperata la results list associata all elemento, senza dover quindi processarlo accedendo all indice invertito o comunque a server supplementari, contestualmente a questa operazione viene rimosso l elemento ed inserito nuovamente in coda in modo tale da renderlo quello più recente, dato che è stato l ultimo ad essere referenziato. É facile intuire come in questo modo l elemento più recente sia sempre in coda alla struttura, mentre quello meno recente e quindi il candidato ad essere rimpiazzato sia sempre in testa. Nel caso invece in cui l elemento non sia presente in cache, allora si procede prima con il classico processamento dell elemento da parte del search engine interrogando l indice invertito, e successivamente nel restituire la results list al client viene ap-

3.2 Result Query Caching 54 plicata anche una politica di replacement nella cache, ossia viene eliminato l elemento (query o url) in testa alla struttura dati e viene inserito il nuovo in coda. Naturalmente quando si parla di elemento in cache si intende la query o url, a seconda dello scenario con l aggiunta delle rispettive informazioni necessarie per la costruzione della pagine dei risultati da restituire all utente. In figura 3.13 viene mostrato il funzionamento e la struttura logica in cui opera la tecnica LRU Query Caching. Fig. 3.13: LRU Query Caching 3.2 Result Query Caching Il primo scenario di Dynamic Query Caching considerato nell ambito dei motori di ricerca è denominato Result Query Caching e consiste nel mantenere in memoria cache le queries con le rispettive results list. Lo studio [2] mostra come circa il 90% degli utenti è tipicamente interessato al più ai primi cinquanta risultati presentati per una query, è quindi necessario mantenere per ogni query in cache circa cinquanta risultati. La figura 3.14 mostra la struttura logica di un classico Query Caching in un motore di ricerca. Il principio di funzionamento è molto semplice ed è il seguente: quando un utente sottopone una query al motore di ricerca, quest ultimo verifica prima se per quella determinata query è mantenuta in memoria cache la rispettiva lista dei risultati, nel caso di Cache Hit

3.2 Result Query Caching 55 (query presente in cache), la results list è ritornata immediatamente all utente riducendo drasticamente il tempo di risposta, altrimenti, in caso di Cache Miss (query non presente in cache), il motore di ricerca la processa normalmente interrogando l indice invertito ed inserendo la query con la rispettiva results list in cache secondo una delle politiche di replacement obiettivo del presente lavoro e proposte nella sezione 3.1. Fig. 3.14: Search Engine with Cache of Query Results 3.2.1 Analisi Query Log Il file di Query Log utilizzato per le simulazioni degli algoritmi è tratto da AOL Search Engine e copre una settimana di interrogazioni effettuate dai vari utenti nel Marzo 2006, per un totale di tre milioni di queries ordinate per un identificatore dell utente. Come prima cosa si è proceduto all ordinamento del file di Log in funzione

3.2 Result Query Caching 56 del tempo di sottomissione delle queries in modo da rispettare il reale afflusso cronologico delle stesse al motore di ricerca, successivamente una prima analisi si è basata sul fatto di determinare quante delle tre milioni di queries fossero distinte. QueryLog Queries Queries Distinte % Queries Distinte AOL 3000000 1344452 44,8 Tabella 3.1: Proprietà Query Log La tabella 3.1 riassume le principali proprietà individuate nel query log utilizzato, inoltre consente di ricavare un upper bound teorico sull Hit Rate raggiungibile assumendo una cache di dimensione infinita e senza usare tecniche di prefetching, cioè quelle tecniche che, in funzione della similarità o vicinanza tra le queries, consentono di caricare in anticipo rispetto a possibili future richieste pagine in cache. Il minimo valore m del Miss Rate raggiungibile è possibile ricavarlo dalla relazione (3.4) ed è pari a: m = D Q = 44, 8% (3.4) dove D è il numero di queries distinte, mentre Q è il numero di queries totali. Dall equazione (3.4) invece è possibile ottenere il massimo Hit Rate (H) mediante la relazione (3.5): H = 1 m = 1 D Q = 55, 2% (3.5) Data la presenza di queries ripetute più volte all interno dello stream, si è proceduto con una ulteriore analisi del file di query log al fine di quantificare la località dei riferimenti tra le queries sottomesse e l influenza che essa ha sulle prestazioni della cache. A tale scopo, come suggerito in [7], sono state individuate le mille query più popolari tramite un algoritmo di data streaming che consente di tener

3.2 Result Query Caching 57 traccia degli elementi, in questo caso queries, più frequenti all interno di uno stream. L algoritmo utilizzato consente di individuare in maniera esatta quale siano le mille queries più frequenti all interno del file di query log, questo approccio anche se costoso dal punto di vista computazionale risulta essere ragionevole in quanto viene effettuato una sola volta ed in più off-line, inoltre garantisce una accuratezza massima. In pratica si tiene traccia di ogni query osservata e di volta in volta vengono mantenute le mille più frequenti. Per la progettazione di tale algoritmo sono stati utilizzati: una tavola hash (Hashtable in Java 6.0) la quale consente di mantenere tutte le query distinte con il rispettivo contatore, in particolare la generica entry (key, value) della tabella hash è costituita da (query, contatore). É bene notare che in una tale struttura hash viene garantita l assenza di query ripetute al suo interno e quindi la corretta individuazione di quante queries distinte vengono osservate. Tuttavia, a causa delll utilizzo di funzioni hash, si ha la possibilità di avere collisioni, ossia queries distinte che vengono mappate su una stessa entry della tabella, e questo può provocare può provocare una diminuzione dell accuratezza nel calcolo delle frequenze delle varie query. Usando funzioni hash ottimizzate, come nel caso di quelle messe a disposizione da Java, allora tale rischio viene ridotto al minimo possibile. un heap minimale (PriorityQueue in Java 6.0) per tenere traccia ad ogni istante delle mille queries più popolari, questo è necessario in quanto la tavola hash non consente di avere entries ordinate per valore dei contatori. Va notato che utilizzare solo un heap minimale per tenere traccia ed in maniera ordinata di tutte le query osservate senza dover ricorrere anche alla tavola hash sarebbe troppo oneroso soprattutto in termini di tempo, in quanto un lookup su una tavola hash è molto più rapido rispetto a quello su un heap minimale. Le tavole hash, infatti, utilizzando funzioni hash, consentono di avere un accesso diretto all elemento richiesto quando si effettua una operazione

3.2 Result Query Caching 58 di lookup e quindi richiedono tempo costante O(1), viceversa in una struttura dati del tipo heap minimale è necessario un tempo lineare per effettuare un lookup. La figura 3.15 mostra il numero di ripetizioni, in scala logaritmica, delle mille queries più popolari, cioè la località spaziale presente nel file di query log utilizzato. In particolare, si può notare come ci siano delle queries effettivamente molto popolari che si ripetono molto spesso, la query più popolare viene sottoposta ben 29821 volte e quella in posizione mille è anch essa abbastanza frequente con 104 ripetizioni. Fig. 3.15: Numero di accessi alle 1000 queries più popolari Nella tabella 3.2 vengono riportati i valori utilizzati nella figura 3.15 per mostrare il comportamento della località spaziale, intesa come il numero di ripetizioni della query più popolare e della decima, centesima, cinquecentesima e millesima più popolari. Nonostante la figura 3.15 mostri come molte delle queries osservate si ripetano all interno dello stream, questa non quantifica la località temporale delle stesse, a tale scopo viene stimato il tempo medio o distanza media che

3.2 Result Query Caching 59 Rank 1 Rank 10 Rank 100 Rank 500 Rank 1000 29821 4451 559 183 104 Tabella 3.2: Località spaziale intercorre tra due successive ripetizioni della stessa query. La distanza media è calcolata come funzione del numero di queries che intercorrono tra due ripetizioni di una stessa query. In tabella 3.3 viene riportato il numero di queries in relazione ad alcuni campioni della distanza, ossia quante queries hanno una distanza media inferiore o uguale a quella presa di volta in volta come campione. Distanza 250 1000 10000 100000 Num. queries 2 13 332 5861 Tabella 3.3: Località temporale delle queries Infine, il comportamento della relazione che c è tra numero di query e distanza media viene mostrato in scala logaritmica nella figura 3.16, dalla quale è possibile osservare come all aumentare della distanza, cioè del numero di queries che separano due ripetizioni di una stessa query, aumenti anche il numero di queries che presentano distanza uguale o minore di quella considerata.

3.3 Result Query Caching con Index Cache 60 Fig. 3.16: Località temporale 3.3 Result Query Caching con Index Cache Il secondo scenario di Query Caching proposto e denominato Result Query Caching con Index Cache risulta essere una particolare alternativa al modo di vedere ed intendere il Query Caching classico così come descritto in 3.2. Tale scenario, su cui non risultano ancora studi o ricerche, si distingue radicalmente dal precedente approccio in quanto si assume l utilizzo di un doppio livello di cache, un primo a livello d indice invertito ed un secondo classico a livello di Query Caching. Sostanzialmente si suppone che un motore di ricerca abbia a disposizione una cache nell indice invertito la quale riesca a fornire per alcune delle queries sottoposte, direttamente le urls contenenti nella pagina dei risultati senza dover interrogare l indice invertito. Invece se la query sottoposta non è presente nell Index Cache allora questa viene processata normalmente tramite l accesso all indice e la corrispondente results list è restituita all utente. Questa cache a livello d indice ha quindi il compito di mantenere per al-

3.3 Result Query Caching con Index Cache 61 cune queries, ad esempio le più recenti o le più frequenti, il corrispondente insieme di urls costituente la results list. Viene poi utilizzato un ulteriore livello di cache denominato per semplicità Result Query Caching il quale mantiene al suo interno le urls ottenute dal precedente livello con ad esempio informazioni aggiuntive quali snippet, titolo, riferimenti, ecc. Risultano evidenti le differenze con il primo approccio di Query Caching proposto in 3.2 in cui viene utilizzato un solo livello di cache per mantenere alcune delle queries più frequenti o recenti con le rispettive results list. É bene notare la sostanziale differenza che vi è tra il mantenere la results list, come nel primo caso, e mantenere le urls come nel secondo caso, per una data query: infatti la results list è l insieme di urls, titoli, snippets, links, ecc. che contenuti ad esempio in una pagina HTML vengono restituiti all utente che ha effettuato l interrogazione al motore di ricerca, mentre mantenere le urls vuol dire mantenere il solo indirizzo del documento in questione e quindi vi è una drastica diminuzione dello spazio necessario a mantenere l informazione tra i due approcci. In figura 3.17 è mostrato lo schema logico di come operi il Result Query Caching con Index Cache all arrivo di una query. I motivi principali che hanno portato allo studio di un approccio al Query Caching di questo tipo sono: il fatto che queries sintatticamente distinte possano avere la stessa results list riuscire ad ottenere la results list di una query come combinazione di quelle di altre queries. Il primo dei due punti specifica la necessità di gestire situazioni in cui queries distinte dal punto di vista sintattico possano avere la stessa results list e quindi sarebbe preferibile riuscire a sfruttare la cache senza dover accedere all indice invertito. Ad esempio le queries Dipartimento Informatica e Sistemistica e D.I.S. sono sintatticamente due queries distinte, anche se molto probabilmente la results list delle due risulta essere molto simile

3.3 Result Query Caching con Index Cache 62 Fig. 3.17: Query Caching con Index Cache se non addirittura uguale. Quindi, mentre nel primo approccio di Query Caching proposto non si avrebbe un match tra le due e quindi risulterebbe un Cache Miss, in questo secondo scenario tale incongruenza viene evitata in quanto vengono gestite direttamente le urls delle results list e non le queries. Infine, il fatto di rappresentare una query come un insieme di urls fornisce la possibilità di riuscire a costruire la results list della query stessa utilizzando le urls uguali (con relative informazioni aggiuntive) già presenti in cache ed appartenenti a queries precedenti eventualmente anche distinte da quella attuale. In figura 3.18 è mostrato un esempio di quanto appena descritto: in particolare, dopo aver osservato tre queries distinte (q 1, q 2, q 3 ) le cui rispettive urls tutte distinte sono memorizzate in cache, ne viene ricevuta una quarta q 4, tramite l Index Cache vengono ottenute in questo caso le tre urls d interesse

3.3 Result Query Caching con Index Cache 63 (url 1, url 8, url 3 ) per q 4. Infine, essendo tutte e tre le urls già presenti in cache (con snippet, titolo, ecc.), la pagina HTML contenente la results list per la query q 4 è costruita come composizione di informazioni ottenute da queries precedenti ed eventualmente distinte. Fig. 3.18: Esempio di utilizzo dell Index Cache Risulta interessante analizzare il caso in cui una url in risposta ad una query dall Index Cache non sia presente nella cache, in tal caso è necessaria una politica di replacement la quale rimpiazzi le urls in base ad un determinato criterio. A tale scopo vengono utilizzate le tecniche presentate in 3.1 apportando solo delle piccole modifiche implementative rispetto alla versione utilizzata per il Query Caching classico 3.2. Quindi, a seconda della tecnica utilizzata, una url in cache viene selezionata per essere eliminata e far posto ad una nuova url in funzione della frequenza (quindi una politica LFU) oppure in funzione di quanto sia recente (politica LRU) o in alternativa in base all ordine con cui sono state inserite in cache (politica FIFO). Si può osservare come a differenza dell approccio di Query Caching 3.2 presentato in precedenza nel quale al verificarsi di un Cache Miss veniva eliminata dalla cache una query e la corrispondente results list in base ad una delle politiche di caching proposte, nel presente scenario con Index Cache si lavora sulla singola url e non sull intera query, questo fa sì che la ri-

3.3 Result Query Caching con Index Cache 64 mozione di una url non implichi la rimozione delle altre urls appartenenti alla stessa query. Sostanzialmente, mentre nel primo scenario si lavorava su un flusso di queries mantenendo in cache query e results list, in questo secondo approccio si lavora su un flusso di urls (in risposta alle stesse queries del primo caso) ma gestite in maniera indipendente l una dall altra, conseguenza di ciò è il fatto che a regime in cache non si potrà più avere una corrispondenza tra le urls e le queries di appartenenza. Con riferimento all esempio di figura 3.18, supponendo che la query q 4 abbia come urls di risposta dall index cache rispettivamente: (url 1, url 8, url 9 ), allora mentre le prime due verrebbero restituite direttamente in quanto presenti in cache, la terza e precisamente url 9 non essendo presente richiederebbe il normale processamento tramite interrogazioni a servers secondari per ottenere snippet, titolo, ecc. e successivamente secondo una politica di replacement prenderebbe il posto di una delle urls mantenute in cache, ad esempio supponendo sia url 1 la url da rimpiazzare si otterrebbe quanto mostrato in figura 3.19. Fig. 3.19: Esempio di replacement A conclusione di quanto detto, nello scenario dell Index Cache le tecniche di Query Caching proposte vengono applicate allo stream di urls supponendo quindi di avere una struttura Index Cache in grado di fornire per ogni data

3.3 Result Query Caching con Index Cache 65 query l insieme delle urls di risposta. Al fine di valutare le prestazioni di tali tecniche in un contesto del genere, sono state utilizzate le API di AJAX Google Search per ottenere le urls di risposta alle queries del file di log (l implementazione viene mostrata in 4.2). Una volta estratte le urls di risposta per ognuna delle queries e salvate in un file, questo viene utilizzato come stream di input ai vari algoritmi di Query Caching per ottenere mediante delle simulazioni dei riscontri prestazionali degli stessi. Nonostante un approccio orientato alla gestione della cache in funzione direttamente delle urls e non delle queries, anche per questo secondo scenario è stata mantenuta traccia indirettamente di queste in modo tale da poterne valutare oltre all Hit Rate ottenuto sulle singole urls anche l Hit Rate sulle queries ottenute come composizione di urls appartenenti ad altre queries. 3.3.1 Analisi URL Log Il file di Log (denominato URL Log) utilizzato in questo secondo approccio di caching è derivato da quello originale di AOL Search Engine contenente tre milioni di query utilizzato in 3.2 ed in particolare è costituito esclusivamente dalle Urls che compongono le results list (tre Urls per ogni query) delle queries estratte dal Query Log. Come già detto, questo insieme di urls, che teoricamente si sarebbero dovute ottenere da un Index Cache, ossia un ulteriore livello di cache a livello d indice rispetto all approccio classico di una singola cache, nell implementazione pratica è ottenuto tramite una sequenza di interrogazioni a Google AJAX Search e precisamente sottoponendogli le tre milioni di queries del file di Query Log. Gli approcci e le metodologie utilizzate in questo scenario per l analisi del file di Log sono del tutto simili a quelli della sezione 3.2.1 per lo scenario di Result Query Caching senza Index Cache, naturalmente a cambiare è il file di log da analizzare. Per questo scenario di caching, il file di log è costituito da circa 8,5 milioni di urls ottenute dalle tre milioni di queries ordinate cronologicamente e, come

3.3 Result Query Caching con Index Cache 66 prima, si individuano quante di queste urls sono distinte e quante sono ripetizioni di stesse urls. É bene notare che in realtà le circa 8,5 milioni di urls sono ottenute per l esattezza da 2832417 queries, in quanto le restanti queries del file di log hanno ottenuto results list vuote. In particolare la tabella 3.4 riassume i principali risultati ottenuti. URL Log Urls Urls Distinte % Urls Distinte AjaxGoogleSearch 8443402 2596782 30,75 Tabella 3.4: Proprietà Url Log Come visto per il caso precedente, è possibile individuare un lower bound m per il Miss Rate della cache tramite la relazione (3.6) assumendo sempre una cache di dimensione infinita: m = D Q = 30, 75% (3.6) dove D è il numero delle urls distinte, mentre Q è il numero delle urls totali. Conseguentemente, il massimo Hit Rate teorico raggiungibile è dato dalla (3.7) H = 1 m = 1 D Q = 69, 25% (3.7) Da una prima analisi, si osserva come la percentuale di urls ripetute (e quindi il massimo Hit Rate teorico raggiungibile) è molto più elevato rispetto a quanto ottenuto in 3.2. Una motivazione a questa forte diversità in termini di prestazioni teoriche è quella della diversa composizione del file di log, il quale, per questo approccio è costituito dalla totalità delle urls che formano le results list e non dalle queries e quindi può accadere che queries distinte possano condividere parte delle rispettive results list e cioè avere delle urls in comune, il che provoca un maggiore numero di ripetizioni. Per quantificare la presenza di località spaziale e temporale all interno del file di log sono state utilizzate le stesse tecniche e considerazioni effettuate in

3.3 Result Query Caching con Index Cache 67 3.2.1, in particolare la tabella 3.5 contiene il numero di ripetizioni delle mille url più richieste. Rank 1 Rank 10 Rank 100 Rank 500 Rank 1000 40111 17505 2030 598 341 Tabella 3.5: Località spaziale Ed in figura 3.20 viene mostrato il comportamento della località spaziale, su scala logaritmica, in funzione dei valori riportati nella tabella 3.5 Fig. 3.20: Numero di ripetizioni delle 1000 urls più popolari Sempre in maniera analoga a quanto fatto in 3.2.1, è stata utilizzata la distanza tra due ripetizioni di una stessa url, espressa come numero di urls che intervallano tale ripetizione, per quantificare la località temporale nello stream di urls ritornate dalle tre milioni di queries contenute nel file di Query Log. Nella tabella 3.6 viene mostrato il numero di urls che presentano una distanza uguale o minore a quella presa in considerazione.

3.3 Result Query Caching con Index Cache 68 Distanza 250 1000 10000 100000 Num. queries 3 13 247 5691 Tabella 3.6: Località temporale delle urls Infine in figura 3.21 viene mostrato l andamento della funzione numero di query ripetute all aumentare della distanza. Fig. 3.21: Località temporale

Capitolo 4 Implementazione Java del Query Caching Indice 4.1 Politche di Query Caching............. 69 4.1.1 Implementazione Space-Saving Query Caching.. 70 4.1.2 Implementazione Optimal-LFU Query Caching.. 71 4.1.3 Implementazione CountMin-Sketch Query Caching 73 4.1.4 Implementazione FIFO Query Caching....... 74 4.1.5 Implementazione LRU Query Caching....... 74 4.2 Implementazione Index Cache........... 75 4.1 Politche di Query Caching In questa sezione viene illustrato in dettaglio come le politiche di Query Caching proposte in 3.1 e le rispettive strutture dati utilizzate possano essere implementate sulla piattaforma di sviluppo Java Standard Edition 6.0 per lo scenario del Result Query Caching, argomento del presente paragrafo. Una premessa valida a tutti gli algoritmi di seguito illustrati consiste nel fatto che senza perdere di generalità e senza influire sulle metriche prestazionali utilizzate, nelle implementazioni degli algoritmi di caching sono state 69

4.1 Politche di Query Caching 70 trascurate, e quindi non gestite, informazioni quali results list, snippet, titolo, ecc. correlate ai rispettivi elementi d interesse. Questa assunzione è stata resa possibile in quanto lo scopo del lavoro presentato è quello di valutare le differenti tecniche di caching proposte in termini di Hit Rate Cache, ossia individuare quale sia la migliore tecnica che consenta di mantenere in cache quegli elementi (queries o urls) che permettono di massimizzare l Hit Rate della stessa. 4.1.1 Implementazione Space-Saving Query Caching Nell implementazione dell algoritmo Space-Saving Query Caching (descritto in dettaglio nella sezione 3.1.1) con tecnologia Java Standard Edition 6.0 sono state utilizzate le seguenti classi: Hashtable <K,V> la quale consente la realizzazione pratica dell omonima struttura dati tavola hash descritta in 3.1.1. Questa funge da cache vera e propria in quanto mantiene al suo interno entries del tipo <key, value>, dove key corrisponde alla query o url a seconda dello scenario considerato, mentre value contiene il valore delle occorrenze dell elemento, cioè il valore del contatore. Al fine di risparmiare spazio, invece di mantenere in cache la query o url vera e propria, ne viene calcolato un ID univoco tramite l utilizzo di una funziona hash ottimizzata fornita dalla classe Object, la quale restituisce un codice intero corrispondente all hash dell elemento osservato e che generalmente occupa molti meno byte di una query testuale che può arrivare anche a più di trenta caratteri. I principali metodi utilizzati per la gestione di tale struttura sono: put(k,v) il quale consente di di inserire un nuovo oggetto all interno della struttura (in particolare la query o url k ed il rispettivo contatore), poi containskey(k) il quale restituisce true nel caso in cui sia presente un elemento con chiave k all interno della tavola hash, ed infine il metodo remove(k) il quale rimuove l elemento con chiave

4.1 Politche di Query Caching 71 k quando questo ad esempio deve essere rimpiazzato da un nuovo elemento, quindi oltre che ad eliminarlo dalla Stream-Summary viene eliminato anche anche dall Hashtable. Come già discusso in precedenza, il motivo principale per cui si è fatto uso di una Hashtable è che questa garantisce tempo costante per i look-ups evitando così scansioni sequenziali dello Stream-Summary. Per quanto riguarda invece l implementazione della Stream-Summary, il cui principio di funzionamento è descritto ed illustrato nella sezione 3.1.1 si è fatto uso: Linkedlist<E>, in particolare, ne è stata utilizzata per mantenere i Buckets che corrispondono ad oggetti Java contenenti una variabile intera contatore ed un ulteriore Linkedlist childlist. Questa ulteriore Linkedlist viene utilizzata per mantenere insieme tutti gli elementi aventi lo stesso valore del contatore. Ogni elemento osservato nello stream viene rappresentato da un oggetto Java contenente l Id dell elemento stesso ed una variabile intera sovrastima. Infine, la Linkedlist dei Buckets è mantenuta ordinata in base al valore del contatore, rendendo computazionalmente semplice l operazione di replacement degli elementi meno frequenti, in quanto essi risiedono necessariamente di volta in volta nel Bucket in testa alla rispettiva Linkedlist corrispondente al Bucket con il minor valore del contatore tra quelli mantenuti. In figura 4.1 viene mostrato lo schema logico di come lo Stream-Summary è realizzato in Java. 4.1.2 Implementazione Optimal-LFU Query Caching Per quanto riguarda l implementazione dell algoritmo Optimal-LFU Query Caching (descritto in 3.1.2) si è fatto uso delle seguenti classi Java: Hashtable <K,V> la quale mantiene un entry <K,V> per ogni elemento distinto e osservato nello stream. La chiave K è rappresentata dall Id

4.1 Politche di Query Caching 72 Fig. 4.1: Stream-Summary in Java dell elemento e stesso ottenuto mediate la funzione Object.hashCode(item e), mentre V corrisponde al valore del contatore, ossia al numero di volte che il rispettivo elemento occorre nello stream. Anche in questo caso la motivazione che ha portato all utilizzo di una simile struttura sta nel fatto che essa garantisce tempo costante per il look-up degli elementi. I principali metodi utilizzati della classe Hashtable<K,V> sono: put(k,v) che consente l inserimento di un elemento all interno della tabella e, nel caso in cui sia già presente un elemento con la stessa chiave, allora quest ultimo viene aggiornato al nuovo valore del campo value, remove(k) il quale rimuove l elemento con chiave k dalla tabella, ed infine il metodo containskey(k) il quale verifica se all interno della tabella è presente già un elemento con chiave k e ritorna un valore booleano. PriorityQueue <E> per la realizzazione di un heap minimale il quale contiene in ogni nodo dell albero un oggetto Java formato dall Id dell elemento, ottenuto tramite la funzione Object.hashCode(item e), ed una variabile intera contatore. Per rendere un oggetto della classe PriorityQueue un heap minimale si è reso necessario effettuare l overriding

4.1 Politche di Query Caching 73 del metodo compareto() al fine di avere gli oggetti con il minimo valore del contatore in alto nell albero (la radice contiene necessariamente l elemento con il minimo valore in assoluto tra quelli mantenuti) mentre gli elementi con un numero di occorrenze elevato verso il basso, cioè le foglie. I principali metodi di tale classe utilizzati sono: contains(object e) che verifica se all interno dell heap sia presente l elemento e, add(object e) il quale consente di inserire l elemento e nella giusta posizione, remove(object e) che permette la rimozione dell elemento e dall heap, ed infine i metodi size() e poll() che permettono rispettivamente di ottenere la dimensione attuale dell heap ed effettuare l estrazione con rimozione dell elemento contenuto nel nodo radice, ossia quello con frequenza minore. I metodi appena elencati sono garantiti avere tempi computazionali pari a: O(log n) per quanto riguarda poll(), add() e remove(), tempo costante per size() ed infine tempo lineare per il metodo contains(). 4.1.3 Implementazione CountMin-Sketch Query Caching Le principali classi Java utilizzate nell implementazione del CountMin-Sketch Query Caching descritto in 3.1.3 sono: PriorityQueue <E>, con lo stesso principio di funzionamento descritto per l algoritmo Optimal-LFU Query Caching in 4.1.2, svolge il ruolo di cache vero e proprio. L elemento E mantenuto in un generico nodo dell heap minimale è rappresentato da un oggetto Java contenente l Id dell elemento stesso ed una variabile intera contatore (la figura 3.8 chiarisce quanto detto). matrice di interi C[][] o di contatori le cui dimensioni (d,w) vengono determinate in funzione di due parametri forniti dall utente (ɛ, δ). Come già illustrato in 3.1.3, il CountMin-Sketch fa utilizzo anche di d funzioni hash le quali consentono di mappare per ogni riga della matrice lo speci-

4.1 Politche di Query Caching 74 fico elemento dello stream sul rispettivo contatore. Le funzioni hash utilizzate sono ottenute mediante il metodo hashcode() della classe Object applicato di volta in volta sull elemento stesso, tuttavia, al fine di rendere le collisioni sempre meno probabili, tali funzioni hash sono state utilizzate in combinazione a numeri casuali generati mediante il metodo Math.random() quando lo Sketch viene inizializzato la prima volta con tutti zero. 4.1.4 Implementazione FIFO Query Caching A differenza delle precedenti tecniche, in cui si è fatto uso di molteplici classi Java per l implementazione delle sofisticate strutture dati, nel FIFO Query Caching (descritto in 3.1.4) viene utilizzata una semplice Linkedlist la quale mantiene al proprio interno gli elementi nell ordine in cui questi sono osservati nello stream. In particolare vengono utilizzati i metodi: addlast(element e) il quale consente di inserire l elemento corrente e in coda alla Linkedlist, removefirst() che permette la rimozione dell elemento in testa alla lista, ad esempio quando un replacement deve essere effettuato, ed infine il metodo contains(element e) per verificare se l elemento e è presente o meno all interno della Linkedlist. Utilizzando questi tre metodi è possibile implementare una coda FIFO tramite l utilizzo di una lista collegata. 4.1.5 Implementazione LRU Query Caching Infine per quanto riguarda l implementazione dell LRU Query Caching (descritto in dettaglio in 3.1.5) si è proceduto in maniera analoga a quanto fatto per il FIFO Query Caching 4.1.4. In particolare, come per il caso precedente, si è fatto ricorso all uso sia di una Linkedlist per la realizzazione di una coda FIFO sia ai metodi quali addlast(element e), contains(element e), removefirst(). I due approcci si differenziano in quanto nell LRU Query Caching viene gestita la freschezza degli elementi e non l ordine con cui questi sono osservati nello stream (infatti in LRU la decisione su quale ele-

4.2 Implementazione Index Cache 75 mento rimpiazzare è presa in base a quanto di recente l elemento sia stato referenziato indipendentemente da quando sia stato inserito in cache), mentre in FIFO la decisione di replacement viene presa in funzione dell ordine con cui gli elementi vengono inseriti in cache e quindi il primo ad essere inserito necessariamente sarà il primo ad essere eliminato quando necessario. Per realizzare quanto appena descritto in LRU Query Caching quando si verifica un Cache Hit, ossia viene verificata la condizione contains(element e)=true, si procede prima con l eliminazione dell elemento stesso tramite il metodo remove(element e) e successivamente con il reinserimento (addlast(element e)) dello stesso in coda alla struttura, in modo tale da risultare come l elemento referenziato più di recente e quindi come l ultimo ad essere momentaneamente candidato alla eliminazione. 4.2 Implementazione Index Cache Come descritto in 3.3, l Index Cache viene intesa come una struttura dati ausiliaria per la realizzazione di un nuovo approccio di Query Caching orientato alla gestione delle urls. Le urls teoricamente contenute in tale struttura dati, e che costituiscono l input per gli algoritmi di Query Caching utilizzati, vengono ottenute utilizzando le API di AJAX Google Search. Queste ultime non sono altro che una libreria Javascript che permette di incorporare Google Search all interno di pagine web fornendo semplici oggetti web i quali effettuano ricerche in linea su una serie di servizi forniti da Google. Come detto, Ajax Google Search viene utilizzato nel presente lavoro al fine di ottenere le results list delle varie queries contenute nel file di log. A tale scopo viene aperta una connessione tra l applicazione in questione e la specifica URL tramite un oggetto URLConnection, in particolare la URL d interesse è la seguente: http://ajax.googleapis.com/ajax/services/search/web? &q a cui di volta in volta viene aggiunta alla fine la query q ed eventualmente

4.2 Implementazione Index Cache 76 vengono specificati altri parametri aggiuntivi come ad esempio il protocollo utilizzato, il numero di documenti da ritornare, ecc. Successivamente viene aperto un BufferedReader per leggere in input sulla connessione aperta, tramite il metodo getinputstream() sempre della classe URLConnection. BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())) Questi dati letti dalla connessione vengono mantenuti in un oggetto di tipo StringBuilder tramite il metodo append() della classe stessa: builder.append(line) Infine, per l elaborazione dei dati ottenuti mediante la connessione, si utilizza una particolare libreria chiamata JSON.org. In paricolare JSON (JavaScript Object Notation) è un semplice formato per lo scambio di dati completamente indipendente dal linguaggio di programmazione. Nello scenario Java, per prima cosa viene costruito un oggetto di tipo JSON, JSONOBJECT, questo è una collezione non ordinata di coppie (nome, valore), esternamente è wrapped in una stringa tra parentesi graffe con i due punti tra i nomi ed i valori e le virgole tra i valori ed i nomi. Il JSONOBJECT al suo interno fornisce metodi come get() e opt() per accedere ai valori in base al nome, put() per aggiungere o sostituire valori in base al nome. In altre parole, un costruttore JSON può essere utilizzato per convertire una forma di testo esterna JSON in una forma interna i cui valori possono essere recuperati con i metodi get() ed opt(), oppure per convertire i valori in un testo JSON utilizzando i metodi put() e tostring(). Quindi: JSONObject json = new JSONObject(builder.toString())

4.2 Implementazione Index Cache 77 L informazione ottenuta tramite le API di Google AJAX Search presenta una struttura del tipo: "responsedata" : { "results" : [], "cursor" : {} } di conseguenza tramite il metodo get() invocato sul nome responsedata è possibile accedere ai valori results e cursor : JSONObject responsedata = (JSONObject) json.get( responsedata ) Successivamente si assegna ad un JSONArray (che non è altro che una sequenza ordinata di valori ed il cui costruttore è in grado di convertire un testo JSON in un oggetto JAVA) il valore del campo results ottenuto tramite il metodo get() sull oggetto responsedata : JSONArray cursor = (JSONArray) responsedata.get( results ) infine si ottiene un JSONObject per ogni risultato contenuto nella results list ed in ordine di rank i tramite il metodo getjsonobject(i) della classe JSONArray: result = cursor.getjsonobject(i) la rispettiva url viene estratta mediante il metodo get() applicato all oggetto result String ris=(string)result.get( url ) dove url è lo specifico campo della struttura result contente l intera url.

Capitolo 5 Analisi sperimentale Indice 5.1 Space-Saving Query Caching............ 79 5.2 Optimal-LFU Query Caching........... 82 5.3 CountMin-Sketch Query Caching......... 83 5.4 FIFO Query Caching................ 85 5.5 LRU Query Caching................. 87 5.6 Confronto prestazionale degli algoritmi..... 88 Al fine di valutare le capacità prestazionali delle varie tecniche di Query Caching proposte nella sezione 3.1 per entrambi gli approcci di caching presi in considerazione (Result Query Caching e Result Query Caching con Index Cache), sono state condotte una serie di simulazioni degli algoritmi stessi. Le metriche prestazionali d interesse nella valutazione degli algoritmi sono: Hit Rate Tempo di esecuzione Hit Rate frazionario (esclusivamente per lo scenario Result Query Caching con Index Cache) 78

5.1 Space-Saving Query Caching 79 Tutti gli esperimenti sono stati condotti su una macchina Linux (Ubuntu Hardy) equipaggiata con processore Dual Core a 2,8 GHz e 1 GB di randomaccess-memory (RAM). In particolare, tali test consistono nell esecuzione di un singolo processo alla volta il quale legge le queries o urls dal file di log e gestisce la cache. Come già detto in precedenza, il file di log fornito come input agli algoritmi contiene tre milioni di queries e, mentre nel caso del Result Query Caching con Index Cache, che utilizza le urls, esso è ottenuto sottoponendo le tre milioni di queries ad Ajax Google Search, nel caso del Result Query Caching classico viene utilizzato il file di log originale. La tabella 5.1 mostra i file di log utilizzati per i due approcci di Query Caching appena descritti. QueryLog Num. Queries Num. Urls AOL 3000000 8443402 Tabella 5.1: File di Log In definitiva, per tutte le tecniche di Query Caching proposte 3.1 vengono presentati i risultati ottenuti in termini di Hit Rate e Tempo di esecuzione al variare della dimensione della cache, intesa come numero di locazioni disponibili. É utile ricordare in tal senso che le simulazioni degli algoritmi avvengono sotto l assunzione che ogni elemento (query o url che sia) occupi nella cache una singola locazione indipendentemente dalla lunghezza in byte dello stesso. Nei seguenti paragrafi verranno mostrati i singoli risultati ottenuti dalle simulazioni dei vari algoritmi di Query Caching per entrambi gli scenari considerati (con o senza Index Cache) e infine verrà presentato un raffronto prestazionale di quanto ottenuto tra tutte le tecniche proposte. 5.1 Space-Saving Query Caching Nella figura 5.1 è mostrato l andamento dell Hit Rate in funzione della dimensione della cache per la tecnica Space-Saving Query Caching sia nello

5.1 Space-Saving Query Caching 80 scenario Results Query Caching sia in quello con Index Cache. Come si può notare, l approccio con Index Cache (rappresentato dal colore verde nell istogramma) raggiunge, a parità di dimensione della cache, un Hit Rate sulla singola url maggiore rispetto all approccio classico basato sulle queries, eccezion fatta per il primo caso di studio, ossia quello in cui la dimensione della cache è pari a mille locazioni, e dove quest ultimo approccio si comporta leggermente meglio. Un simile comportamento è dovuto a quanto già detto in precedenza, ossia al fatto che queries distinte possono avere results list uguali o comunque in parte condivise, quindi la probabilità di trovare un singola url all interno della cache è senza dubbio maggiore, naturalmente anche il fatto di utilizzare un file di input molto più grande (come mostrato nella tabella 5.1) potrebbe essere causa di un leggero miglioramento di tale metrica prestazionale. Fig. 5.1: Space-Saving Hit Rate Nella tabella 5.2 vengono mostrati in dettaglio i risultati ottenuti dalla simulazione dello Space-Saving Query Caching al variare della dimensione della cache, in particolare nella seconda riga sono mostrati gli Hit Rates

5.1 Space-Saving Query Caching 81 raggiunti dall algoritmo nello scenario senza Index Cache, mentre nella riga successiva quelli per lo scenario con Index Cache. DIM. CACHE 1000 5000 10000 50000 100000 HIT-Query(%) 0,27 0,35 0,38 0,44 0,47 HIT-Url(%) 0,26 0,39 0,43 0,52 0,55 Tabella 5.2: Space-Saving Hit Rate Per quanto riguarda invece il tempo di esecuzione dell algoritmo (espresso in secondi) per entrambi gli scenari di Query Caching considerati, si può notare come banalmente all aumentare della dimensione della cache aumenti anche il tempo necessario a processare i rispettivi file di log presi in input, come mostra la figura 5.2. Si può notare come raddoppiare la dimensione della cache da 50000 a 100000 locazioni comporti all incirca il raddoppio del tempo di esecuzione dell algoritmo. Fig. 5.2: Space-Saving Execution Time I tempi di esecuzione dell algoritmo necessari al processamento del file di log all aumentare della dimensione della cache sono riportati nella tabella 5.3.

5.2 Optimal-LFU Query Caching 82 DIM. CACHE 1000 5000 10000 50000 100000 Time-Query(sec) 77 630 1429 6741 12802 Time-Url(sec) 225 1619 3718 16376 31942 Tabella 5.3: Space-Saving Execution Time 5.2 Optimal-LFU Query Caching La figura 5.3 mostra le prestazioni in termini di Hit Rate raggiunte dall algoritmo Optimal -LFU Query Caching per entrambi gli scenari di Query Caching presi in considerazione in funzione della dimensione della cache. Banalmente anche per l Optimal -LFU all aumentare della dimensione della cache aumenta l Hit Rate raggiunto, ed anche in questo caso l approccio orientato alle urls, cioè con Index Cache, consente di ottenere un Hit Rate maggiore per tutte le dimensioni di cache considerate. Fig. 5.3: Optimal-LFU Hit Rate nello specifico, i valori utilizzati per ottenere il grafico in figura 5.3 sono quelli riportati con precisione nella tabella 5.4. Contrariamente a quanto visto per tutti gli altri algoritmi di Query Caching

5.3 CountMin-Sketch Query Caching 83 DIM. CACHE 1000 5000 10000 50000 100000 Time-Query(%) 0,135 0,22 0,234 0,334 0,381 Time-Url(%) 0,15 0,22 0,26 0,374 0,43 Tabella 5.4: Optimal-LFU Hit Rate proposti, per l Optimal LFU Query Caching non sono stati presi in considerazione i tempi di esecuzione, in quanto si è reso necessario ricorrere all utilizzo di una macchina server nettamente più potente di quella utilizzata ed evidentemente questi tempi risultano essere poco significativi in un contesto di confronto tra vari algoritmi. Tutto ciò è dovuto al fatto che l Optimal LFU Query Caching, che mantiene il conteggio esatto delle occorrenze di tutti gli elementi distinti presenti nello stream, necessita di una quantità di memoria rilevante al punto tale da non essere eseguibile sulla macchina utilizzata per la simulazione di tutti gli altri algoritmi di Query Caching. 5.3 CountMin-Sketch Query Caching L algoritmo CountMin-Sketch Query Caching, come illustrato nella sezione 3.1.3, necessita di due parametri utente (ɛ, δ) i quali rappresentano rispettivamente l errore tollerato e la probabilità limite con cui questo è garantito. Da questi parametri si ottiene la dimensione della matrice di contatori utilizzata dall algoritmo secondo l equazione 3.2. Per la simulazione i parametri sono stati settati rispettivamente a: ɛ = 0, 001 e δ = 0, 001, ottenendo così una matrice di contatori di dimensioni pari a (7 x 2719). Come per i precedenti algoritmi, la figura 5.4 mostra l andamento dell Hit Rate in funzione della dimensione della cache per l algoritmo CountMin-Sketch Query Caching. La tabella 5.5 mostra in dettaglio i valori dell Hit Rate raggiunti dall algoritmo, dai quali si può osservare ancora una volta come l aumento della dimensione della cache comporta un miglioramento dell Hit Rate, tuttavia, diversamente dagli approcci precedenti l algoritmo orientato alla gestione delle

5.3 CountMin-Sketch Query Caching 84 Fig. 5.4: CountMin-Sketch Hit Rate queries ottiene prestazioni migliori rispetto a quello orientato alla gestione delle urls quando si considerano cache di dimensioni medio-piccole. DIM. CACHE 1000 5000 10000 50000 100000 Time-Query(%) 0,136 0,208 0,245 0,367 0,432 Time-Url(%) 0,136 0,188 0,23 0,38 0,47 Tabella 5.5: CountMin-Sketch Hit Rate I tempi di esecuzione necessari all algoritmo per il processamento dei rispettivi file di log in input sono mostrati nella tabella 5.6 da cui si ottiene quanto mostrato in figura 5.4. Risulta evidente come un tale algoritmo necessiti di un tempo computazionale molto maggiore rispetto ai precedenti, in quanto, essendo basato su un modello di streaming Sketch-Based, per ogni aggiornamento della struttura è necessario il calcolo di più funzioni hash e l aggiornamento di più contatori, precisamente tante volte quante sono le righe della matrice.

5.4 FIFO Query Caching 85 DIM. CACHE 1000 5000 10000 50000 100000 Time-Query(sec) 313 2833 6041 31170 63577 Time-Url(sec) 832 8087 17460 90868 188101 Tabella 5.6: CountMin-Sketch Execution Time Fig. 5.5: CountMin-Sketch Execution Time 5.4 FIFO Query Caching Anche per l algoritmo FIFO Query Caching sono state condotte analoghe simulazioni al variare della dimensione della cache, ottenendo i risultati, in termini di Hit Rate, mostrati nella tabella 5.7 e graficati in figura 5.6 DIM. CACHE 1000 5000 10000 50000 100000 Time-Query(%) 0,25 0,333 0,36 0,419 0,44 Time-Url(%) 0,233 0,36 0,4 0,49 0,525 Tabella 5.7: FIFO Hit Rate Come si può notare, l algoritmo FIFO Query Caching raggiunge un Hit Rate in cache molto elevato, sui livelli dello Space-Saving Query Caching, nonostante non usi nessuna euristica basata sulla frequenza degli elementi, ma si basa semplicemente sull ordine di arrivo degli elementi in cache, ossia il primo degli elementi ad essere inserito in cache è anche il primo ad essere

5.4 FIFO Query Caching 86 Fig. 5.6: FIFO Hit Rate eliminato quando necessario, indipendentemente da quanto e quando sia stato richiesto in passato. Anche in questa circostanza si ottengono risultati migliori nello scenario orientato al processamento delle urls rispetto a quello orientato al processamento delle queries. La figura 5.7 mostra il tempo di esecuzione necessario all algoritmo per i due scenari di Query Caching in funzione della dimensione della cache. In controtendenza a quanto visto in termini di Hit Rate, in cui l approccio con Index Cache come detto raggiunge prestazioni migliori, per quanto riguarda il tempo di esecuzione, poiché si ha la necessità di processare un numero di elementi molto maggiore, è richiesto un tempo più elevato rispetto allo scenario senza Index Cache. I risultati ottenuti sono rappresentati nella tabella 5.8 DIM. CACHE 1000 5000 10000 50000 100000 Time-Query(sec) 62 611 1636 7164 14885 Time-Url(sec) 180 2416 4419 17957 34396 Tabella 5.8: FIFO Execution Time

5.5 LRU Query Caching 87 Fig. 5.7: FIFO Execution Time 5.5 LRU Query Caching Infine, anche per l algoritmo LRU Query Caching vengono mostrati i risultati ottenuti dalle simulazioni effettuate per i due scenari di Query Caching, in particolare la figura 5.8 mostra l andamento dell Hit Rate raggiunto dall algoritmo all aumentare della dimensione della cache. Per un maggior dettaglio viene proposta la tabella 5.9 la quale riporta gli Hit Rates raggiunti per ogni dimensione della cache presa considerazione. DIM. CACHE 1000 5000 10000 50000 100000 Time-Query(%) 0,267 0,345 0,372 0,434 0,462 Time-Url(%) 0,255 0,377 0,423 0,5 0,54 Tabella 5.9: LRU Hit Rate In maniera analoga la figura 5.9 mostra l andamento della funzione Tempo di esecuzione anch essa al variare della dimensione della cache. Anche in questo caso l approccio con Index Cache richiede un maggiore tempo computazionale a causa di un maggior numero di elementi da processare. Infine la tabella 5.10 riassume i valori dei tempi di esecuzione dell algoritmo LRU Query Caching.

5.6 Confronto prestazionale degli algoritmi 88 Fig. 5.8: LRU Hit Rate DIM. CACHE 1000 5000 10000 50000 100000 Time-Query(sec) 78 906 2340 11343 23702 Time-Url(sec) 214 3237 6784 34664 72148 Tabella 5.10: LRU Execution Time 5.6 Confronto prestazionale degli algoritmi Prima di fornire un analisi prestazionale confrontando i vari algoritmi proposti in termini di Hit Rate ed Execution Time, è interessante mostrare un ulteriore grafico il quale mette in relazione il Query Hit Rate raggiunto dagli algoritmi in uno scenario orientato alla gestione delle urls, cioè in presenza di un Index Cache. Come detto in precedenza, uno dei motivi per cui questo approccio viene proposto è quello di offrire la possibilità di costruire le results list delle varie queries utilizzando più sottoinsiemi di quelli delle altre queries che sono mantenute in cache. Viene considerato un Query Hit in cache quando tutte le urls associate ad una query e ritornate tramite un Index Cache sono momentaneamente presenti all interno della cache, quindi non si rende necessaria al motore di ricerca l interazione con altri servers per recuperare informazioni inerenti a nessuna delle urls ritornate. A tal proposito è signi-

5.6 Confronto prestazionale degli algoritmi 89 Fig. 5.9: LRU Execution Time ficativo l esempio di figura 3.18 in cui tutte le urls di q 4 sono presenti in cache. In base a come è stato definito precedentemente il Query Hit Rate, il grafico di figura 5.10 mostra l andamento di tale misura in funzione della dimensione della cache per ognuno degli algoritmi di Query Caching proposti. Per una maggiore precisione la tabella 5.11 riporta i Query Hit Rate ottenuti dalle simulazioni dei vari algoritmi. DIM. CACHE 1000 5000 10000 50000 100000 SpaceS.(%) 0,222 0,326 0,367 0,446 0,479 CountS.(%) 0,08 0,107 0,123 0,22 0,317 LFU(%) 0,097 0,15 0,19 0,285 0,33 FIFO(%) 0,192 0,299 0,338 0,411 0,442 LRU(%) 0,21 0,32 0,362 0,439 0,471 Tabella 5.11: Query Hit Rate Analizzando in dettaglio i risultati mostrati nella tabella 5.11 si osserva come i Query Hit Rates che i vari algoritmi raggiungono nello scenario di caching orientato alle urls sono decisamente inferiori rispetto a quelli raggiunti dagli stessi considerando le singole urls. Quanto appena descritto risulta ovvio a seguito del fatto che per avere un Hit Query è necessario che tutte le urls in risposta ad una query siano presenti all interno della cache, men-

5.6 Confronto prestazionale degli algoritmi 90 Fig. 5.10: QUERY HIT RATE tre, se consideriamo solo la singola url, per avere un Hit Url è sufficiente che solo questa sia presente, indipendentemente dalle altre urls appartenenti alla stessa query. Risulta più interessante il confronto tra Query Hit Rate raggiunto in uno scenario con Index Cache e quello raggiunto in un classico scenario di Query Caching in cui vengono mantenute in cache le singole queries. In tal senso si può notare, confrontando la tabella 5.11 con quelle proposte nelle sezioni precedenti dei singoli algoritmi, come le prestazioni in termini di Query Hit Rate siano sostanzialmente equivalenti, eccezion fatta per il CountMin-Sketch Query Caching il quale presenta un degrado in media del 10% circa a svantaggio dello scenario orientato alle urls. La similarità delle prestazioni deriva principalmente dal fatto che le urls gestite in uno dei due contesti sono ottenute direttamente dalle queries utilizzate nell altro, quindi ripetizioni di stesse queries coincidono con altrettante ripetizioni delle rispettive urls, gli unici indici di variazione sono le possibili collisioni dovute all utilizzo delle funzioni hash nello streaming degli elementi e la possibilità di avere urls condivise tra queries distinte e che in linea del tutto teorica