• Non ci sono risultati.

3.4 Realizzazione del Modulo di Traffic Assessment

3.4.1 Descrizione delle Classi

Questa classe rappresenta la classe di avvio del sistema. Da questa classe vengono avviati i thread relativi alle classi di Capturing-Filtering e Selection-Assessment. Inoltre si occupa si leggere tutti i file di configurazione e memorizzarne i risultati in una istanza della classe Config che poi verrà trasmessa alle istanze delle classi rappresentati i moduli del Sistema.

Una volta avviati i moduli, resta in attesa che questi terminino per poter terminare l’esecuzione dell’intero sistema.

Come è stato specificato nel parametro precedente, è possibile avviare tutti i moduli o soltanto parte di essi. Pertanto il metodo start_system() controlla quali moduli sono stati abilitati e li mette in esecuzione.

/**

* Costruttore della Classe

Inizializza l'oggetto Config con le configurazioni lette dai files .conf */

public TrafficAssessmentPlatform() { //leggo il file di configurazione

myConfig=new Config(System.getProperty("user.dir")); }

72 Google_Places.java

Questa classe rappresenta la classe che interroga il servizio di Google Places pasaando come input una coppia di coordinate e ritornando in output una lista di luoghi di interesse all’interno di un raggio di N Km dove N rappresenta un parametro della funzione che permette di individuare i punti di interesse.

Di seguito viene riportato il metodo che interroga il servizio Google Places. /**

* Questa metodo avvia il sistema.

* A seconda delle configurazioni specificate nel file platform.conf vengono avviati i vari moduli */

private void startSystem(){

if(myConfig.getModules(0)) {

//avvio il modulo di capturing

c=new Capturing(myConfig); c.start();

}

if(myConfig.getModules(1)) {

//avvio il modulo di Selection

s=new Selection(myConfig); s.start();

} }

public ArrayList<Place> searchNearby(double lat, double lng, int radius) { ArrayList<Place> resultList = null;

HttpURLConnection conn = null;

StringBuilder jsonResults = new StringBuilder(); try {

//creo la stringa della query

StringBuilder sb = new StringBuilder(PLACES_API_BASE); sb.append(TYPE_SEARCH);

sb.append(OUT_JSON); sb.append("?sensor=false"); sb.append("&key=" + API_KEY);

sb.append("&location=" + String.valueOf(lat) + "," + String.valueOf(lng)); sb.append("&radius=" + String.valueOf(radius));

URL url = new URL(sb.toString());

//mi connetto al servizio e attendo i risultati

conn = (HttpURLConnection) url.openConnection();

InputStreamReader in = new InputStreamReader(conn.getInputStream()); int read;

char[] buff = new char[1024];

while ((read = in.read(buff)) != -1) { jsonResults.append(buff, 0, read); }

} catch (MalformedURLException e) {

System.err.println ("Error processing Places API URL"); return resultList;

} catch (IOException e) {

System.err.println ( "Error connecting to Places API"); return resultList;

73 Road.java

Questa classe rappresenta una strada ed è utilizzata per convertire i risultati del modulo TrafficJamDetector in coordinate GPS da utilizzare per l’interrogazione del servizio di Google Places attraverso il metodo visto in precedenza.

Per ogni strada vengono memorizzata le coordinate di inizio e fine in formato GPS e quelle nel formato utilizzato dal modulo di TrafficJamDetector. In questo modo sarà quindi possibile ricavare la posizione in formato di coordinata GPS a partire da quella in formato Repast del segmento iniziale del traffico rilevato.

Config.java

Questa classe rappresenta l’insieme delle configurazioni del sistema così come sono specificate nei files dedicati. Questa classe viene utilizzata da tutti i componenti principali del modulo e viene inizializzata all’avvio all’interno del costruttore della classe traffic_assessment_platform. } finally { if (conn != null) { conn.disconnect(); } } try {

// Creo un oggetto JSON in cui sono contenuti i risultati

JSONObject jsonObj = new JSONObject(jsonResults.toString()); JSONArray predsJsonArray = jsonObj.getJSONArray("results"); // Estraggo i punti di interesse dai risultati dell'interrogazione

resultList = new ArrayList<Place>(predsJsonArray.length()); for (int i = 0; i < predsJsonArray.length(); i++) {

Place place = new Place();

place.name = predsJsonArray.getJSONObject(i).getString("name");

JSONObject geometry = predsJsonArray.getJSONObject(i).getJSONObject("geometry"); JSONObject location = geometry.getJSONObject("location");

Double lt = location.getDouble("lat"); Double ln = location.getDouble("lng");

place.reference = lt.toString()+","+ln.toString(); resultList.add(place);

}

} catch (JSONException e) {

System.err.println ("Error processing JSON results : " + e.toString()); }

return resultList; }

74

Come possiamo notare, il metodo readPlatformConfig viene eseguito prima di tutti gli altri e che si occupa di settare correttamente tutti i parametri fondamentali contenuti nel file platform.conf. Inoltre questo metodo permette anche di convertire l’output del modulo precedente e interrogare il servizio di Google Places attraverso la classe dedicata. I risultati dell’interrogazione verranno aggiunti alle keyword di filtraggio del modulo di Capturing.

Di seguito è raprresentato il diagramma che rappresenta il funzionamento della classe Config per la lettura delle impostazioni.

Figura 31 - Schema di Funzionamento della classe Config

MySQL_Bridge.java

Questa classe rappresenta l’insieme delle funzioni che permettono di interfacciarsi con il database MySQL utilizzato per la memorizzazione dei dati. In particolare la classe permette di eseguire le seguenti azioni:

public Config(String path){ this.path=path;

//PLATFORM readPlatformConfig(); //CAPTURING readCapturingConfig(); //FILTERING readFilteringConfig(); //SELECTION readSelecionConfig(); //ASSESSMENT readAssessmentConfig(); //normalizzo le keyowrds if(keywords.endsWith(",")){

keywords=keywords.substring(0,keywords.length()-1); }

75

• Connessione al DB specificando i parametri di connessione

• Selezione di Dati da una specifica tabella del DB

• Inserimento, Modifica ed Eliminazione di Dati

• Chiusura della Connessione

MessageConsole.java

Questa classe rappresenta la console testuale utilizzata per visualizzare i messaggi che generano i moduli di Capturing, Filtering, Selection e Assessment. La scelta di implementare una console non utilizzando quella di sistema , è stata dettata dal fatto che in questo modo è stato possibile separare i flussi di messaggi mandati in output dai vari moduli e formattarli in maniera più riconoscibile per l’utilizzatore. Inoltre attraverso il comando CTRL+S è possibile terminare l’esecuzione di un modulo in maniera non distruttiva rispetto alla classica terminazione da console CTRL+C.

Di seguito viene riportato il metodo che permette una stampa formattata sulla console. public MySQLBridge(String server,String user,String passwd,String db) throws

ClassNotFoundException,SQLException{

// Caricamento dei driver per la connessione al DB

Class.forName("com.mysql.jdbc.Driver");

//inizializzo la connessione al DB connect =

DriverManager.getConnection("jdbc:mysql://"+server+"/"+db+"?"

+ "user="+user+"&password="+passwd); }

public ResultSet retrieveData(String query) throws SQLException{

//invio una richiesta al DB

Statement statement = connect.createStatement();

//l'oggetto resultSet raccoglie i risultati della query

ResultSet resultSet = statement.executeQuery(query); return resultSet;

}

public void insertData(String query) throws SQLException{

//invio una richiesta al DB

Statement statement = connect.createStatement();

//eseguo la query di inserimento/modifica/eliminazione

statement.executeUpdate(query); statement.close();

}

public void closeConnection() {

//chiudo tutti gli oggetti del DB

try {

if(connect!=null) connect.close(); } catch (SQLException e) {

System.err.println(e.getMessage()); System.exit(1);

} }

76

Nel dettaglio vengono utilizzate due console, una per i moduli di Capturing e Filtering e un’altra per quelli di Selection e Assessment. Sulla console di Capturing e Filtering viene visualizzato in output il Timestamp dell’ultimo messaggio catturato insieme col numero totale di messaggi catturati da parte del Modulo di Capturing e vengono visualizzati messaggi inerenti al filtraggio per quanto riguarda il modulo di Filtering come ad esempio se un tweet non viene salvato in quanto risulta vuoto dopo le operazioni di filtraggio.

Per quanto riguarda la console relativa ai moduli di Selection e Assessment, in realtà questa viene utilizzata soltanto dal modulo di Selection in maniera analoga a quella del modulo di Capturing. Per ispezione visiva è possibile effettuare anche un controllo sul numero di tweet che vengono catturati e quelli effettivamente salvati.

Capturing.java

Questa classe rappresenta il modulo di Data Capturing precedentemente illustrato. Si tratta di una classe che rappresenta un thread separato rispetto a quello principale.

Come specificato nella sezione relativa al file di configurazione platform.conf , è possibile avviare questo modulo in due diverse modalità :

• Modalità Stream in Tempo Reale

In questa modalità viene eseguita un interrogazione a Twitter con le keyword specificate in precedenza; il modulo quindi si mette in ascolto del canale di comunicazione rappresentato dallo stream di Tweet e cattura quei tweet che hanno una corrispondenza con le keyword specificate nella query. Inoltre, grazie alle altre impostazioni presenti nel file capturing.conf, il modulo scarta quei tweet che non corrispondono ai settaggi precedentemente impostati. public void printMessage(String message,Color c){

StyledDocument doc = textComponent.getStyledDocument(); Style style = textComponent.addStyle("My Style", null);

StyleConstants.setForeground(style, c); try {

if(!isAppend) doc.insertString(0, message+"\n\r",style); else doc.insertString(doc.getLength(), message+"\n\r",style); }

catch (BadLocationException e){} }

77

Figura 32 - Funzionamento del componente di Capturing in modalità tempo reale

Di seguito è riportato il codice relativo ai due blocchi funzionali riportati nella figura precedente.

Il primo blocco si preoccupa di stabilire la connessione a Twitter.

Il secondo si occupa di intercettare lo stream di tweet. …

//apro lo stream

twitterStream.addListener(listener);

ArrayList<String> track = new ArrayList<String>(); ArrayList<Long> follow = new ArrayList<Long>();

//imposto i filtri

track.addAll(filtro);

long[] followArray = new long[follow.size()]; for (int i = 0; i < follow.size(); i++) { followArray[i] = follow.get(i); }

String[] trackArray = track.toArray(new String[track.size()]);

twitterStream.filter(new FilterQuery(0, followArray, trackArray)); …

StatusListener listener = new StatusListener() {

@Override

public void onStatus(Status status) { //aplico le configurazioni

if(conf.keepReply()==false){

if(status.getInReplyToStatusId()!=-1) return; }

if(conf.keepRetweet()==false){ if(status.isRetweet()) return; }

if(conf.getLanguage().equals(status.getLang())==false) return;

//inserisco il messaggio nella lista capturedTweet++;

passToFiltering(status); }

78

• Modalità DEMO

In questa modalità non viene eseguita alcuna interrogazione a Twitter ma viene fornito come input al modulo un file di testo contente diverse linee, ognuna rappresentante un tweet. Inoltre, sempre grazie alle altre impostazioni presenti nel file capturing.conf, il modulo scarta quei tweet che non corrispondono ai settaggi precedentemente impostati; tuttavia in questa modalità sono possibili operazioni soltanto per quanto riguarda i possibili Retweet in quanto dal solo testo del messaggio non è possibile ricavare informazioni su eventuali Replay e sulla lingua.

Entrambi le modalità richiamano la funzione passToFiltering(), la quale non fa altro che stampare un messaggio sulla console ed invocare il metodo corrispondente del modulo di Filtering.

Filtering.java

Questa classe rappresenta il modulo di Data Filtering precedentemente illustrato. Questo modulo viene utilizzato ogni volta che dal modulo precedente di Capturing è stato catturato un tweet; a questo vengono applicati i filtri specificati nel file

public void DEMO_Capturing(String file) { setDemo(true);

InputStream inputstream = null; List<String> lines = null; try {

//leggo il file DEMO

inputstream = new FileInputStream(file); lines=IOUtils.readLines(inputstream); } catch (IOException e) {

console.printMessage(e.getMessage(),Color.red); }

for(int i=0;i<lines.size();i++){ if(conf.keepRetweet()==false){

if(lines.get(i).contains("RT")) continue; }

//ricavo il timestamp

java.util.Date date= new java.util.Date(); //stampo il messaggio

console.printMessage(new Timestamp(date.getTime())+" - Captured Tweets : "+ (i+1),Color.yellow);

//filtering

f.applyFilters_DEMO(i,lines.get(i),new Timestamp(date.getTime())); }

}

private void passToFiltering(Status item){

//ricavo il timestamp

java.util.Date date= new java.util.Date(); //stampo il messaggio

console.printMessage(new Timestamp(date.getTime())+" - Captured Tweets : "+ capturedTweet,Color.yellow); //passo al filtering

f.applyFilters(item); }

79

filtering.conf ed in seguito, se non è vuoto, viene salvato nella tabella filtering del database MySQL.

Il metodo principale di questa classe è quello che seleziona gli attributi da mantenere rispetto al tweet (solo modalità in tempo reale) che viene passato come argomento; in mdalità DEMO questo metodo non viene eseguito in quanto i tweet sono già in un formato standard per l’elaborazione delle informazioni. Di seguito si riporta parte del codice.

L’operazione di filtraggio degli attributi viene svolta principalmente per ragioni di risparmio sullo spazio di archiviazione dei tweet nel database MySQL in quanto non tutti gli attributi risultano effettivamente rilevanti a questo punto dell’elaborazione. Sono obbligatori soltanto gli attributi ID e TEXT.

Selection.java

Questa classe rappresenta il modulo di Data Selection precedentemente illustrato. Questo modulo viene utilizzato ogni volta che dal modulo di Filtering viene salvato un tweet nella rispettiva tabella; tale tweet viene catturato dal modulo di selection , filtrato in accordo a quanto impostato nel file di configurazione e successivamente salvato nella tabella selection del database MySQL.

Figura 33 - Funzionamento del componente di Selection

private Map<String, String> selectAttributes(Status tweet){

Map<String, String> attributes = new HashMap<String, String>();

//seleziono gli attributi dalla lista

for(int j=0;j<conf.getFilters(0).size();j++){ switch(conf.getFilters(0).get(j)){ case "<ATTRIBUTO>":

<SALVO L’ATTRIBUTO>

} }

80

Per quanto riguarda il filtraggio del messaggio del tweet, oltre al filtraggio impostato per mezzo del file di configurazione, vengono applicati altri filtri di default quali quelli sui link, sulle lettere accentate e sugli spazi ripetuti. Nella casella successiva viene riportato parte del codice del metodo che effettua il filtraggio del testo del tweet.

Assessment

Questa classe rappresenta il modulo di Event Assessment precedentemente illustrato. Questo modulo viene utilizzato ogni volta che si vuole generare un Tag Cloud relativamente a ciò che contiene la tabella selection del Database MySQL. In particolare il contenuto della tabella viene salvato nel file assessment.txt che viene dato in input al servizio di Tag Cloud.

private String filterTweet(String testo){

//tolgo i link

testo=testo.replaceAll("https?://\\S+\\s?", "");

//normalizzo gli spazi

<NORMALIZZAZIONE DEGLI EVNTUALI SPAZI RIPETUTI> //applico i filtri

StringTokenizer st = new StringTokenizer(testo); String myText="";

while (st.hasMoreElements()) { String word=st.nextToken();

//filtro le keywords

for(int i=0;i<conf.getKeywords().split(",").length;i++){

if(conf.getKeywords().split(",")[i].equals(" "+ word +" ")) word=" "; }

//rimuovo le accentate

<RIMOZIONE DI TUTTE LE ACCENTATE> //normalizzo apostrofi e doppi apici <NORMALIZZAZIONE DI APICI E DOPPI APICI>

//applico filtri punteggiatura,stop words,baseline e bad words

for(int i=1;i<5;i++){

//per ogni parola/punteggiatura applico una sostituzione

for(int j=0;j<conf.getFilters(i).size();j++){ switch(i){

case 1:

word=word.replaceAll(java.util.regex.Pattern.quote(conf.getFilters(i).get(j)), " ");

break; default:

if(conf.getFilters(i).get(j).equals(word)) word=" "; break; } } } myText=myText.trim() + " " +word.trim()+ " "; } testo=myText;

//normalizzo nuovamente gli spazi

<NORMALIZZAZIONE DEGLI EVENTUALI SPAZI RIPETUTI>

81

Il servizio di Tag Cloud utilizza la libreria kumo per calcolare le frequenze degli n- grammi presenti nella raccolta di tweet. In particolare vengono estratti prima tutti gli uni-grammi presenti, dopodiché vengono estratti un certo numero di N-Grammi con cardinalità massima specificata nel file di configurazione ed infine le due liste vengono fuse utilizzando come regola di pesatura degli N-Grammi rispetto agli uni-grammi quella illustrata in precedenza. Inoltre vengono eliminati dalla lista di termini tutti quegli uni-grammi che sono sinonimi di un uni-gramma con peso in frequenza più elevato.

//recupero da Selection tutti gli elementi ResultSet resultSet = null;

try {

resultSet = myDB.retrieveData("SELECT text FROM selection;"); } catch (SQLException e) {

console.printMessage(e.getMessage(),Color.red); }

if(resultSet!=null){

//scrivo ogni record su una riga del file assessment.txt

PrintWriter out = null; try {

out = new PrintWriter("assessment.txt"); } catch (FileNotFoundException e) {

console.printMessage(e.getMessage(),Color.red); } try { while (resultSet.next()) { out.println(resultSet.getString("text")); } } catch (SQLException e) {

console.printMessage(e.getMessage(),Color.red); }

out.close(); try {

resultSet.close(); } catch (SQLException e) {

console.printMessage(e.getMessage(),Color.red); }

}

//creo la lista di parole ordinate in frequenza

List<WordFrequency> wordFrequencies = null; List<WordFrequency> nGrams=null;

try {

//unigrammi

wordFrequencies = frequencyAnalizer.load(getInputStream(conf.getPath()));

//N-Grammi

nGrams = includeNGrams(getInputStream(conf.getPath())); } catch (IOException e) {

console.printMessage(e.getMessage(),Color.red); }

//fusione delle liste

List<WordFrequency> newList=createNewList(nGrams,wordFrequencies); controllaSinonimi(newList);

82

La lista di termini viene quindi utilizzata per generare la nuvola, le cui caratteristiche come dimensioni e numero di parole sono state impostate attraverso il file di configurazione. Ogni ciclo di generazione di Tag Cloud porta alla creazione di un file di tipo PNG denominato tag_cloud.png.

//Generazione della Cloud

WordCloud wordCloud = new WordCloud(this.conf.getAssessmentParameters(3), this.conf.getAssessmentParameters(4), CollisionMode.RECTANGLE);

wordCloud.setPadding(1);

wordCloud.setBackground(new RectangleBackground(this.conf.getAssessmentParameters(3), this.conf.getAssessmentParameters(4)));

wordCloud.setColorPalette(buildRandomColorPallete(40)); wordCloud.setFontScalar(new LinearFontScalar(15, 50));

wordCloud.setAngleGenerator(new AngleGenerator((conf.getAssessmentParameters(5)*- 1),conf.getAssessmentParameters(5),conf.getAssessmentParameters(6)));

wordCloud.build(this.frequencyAnalizer.takeTopFrequencies(newList)); wordCloud.writeToFile("tag_cloud.png");

83

4 Testing del Sistema

Il testing del Sistema è stato effettuato in due differenti fasi :

1. nella prima fase è stato testato il modulo di Traffic Detection utilizzando come sorgente per i casi di test il simulatore di traffico introdotto nel capitolo precedente. In particolare è stato testata l’efficacia dell’ottimizzazione mediante Differential Evolution rispetto alla configurazione manuale dei parametri.

2. Per quanto riguarda il modulo di Traffic Assessment è stato utilizzato un Dataset di Tweet riguardanti la piena dell’Arno del 31/01/2014. Il modulo è stato inizialmente testato senza l’utilizzo di filtri e individuando soltanto uni-grammi per poi andare successivamente ad affinare il livello di rilevazione introducendo prima una serie di filtri ed in seguito il supporto anche agli N-grammi.

Documenti correlati