I 10 pacchetti Flutter migliori e più popolari

Flutter è il toolkit di Google per la creazione di bellissime applicazioni compilate in modo nativo per dispositivi mobili, Web e desktop da una singola base di codice.

Flutter è basato sul linguaggio di programmazione Dart. Ha una comunità ampia e vivace su Dart.dev, che offre sia pacchetti supportati ufficialmente che di terze parti per rendere lo sviluppo su Flutter ancora più produttivo.

Questo articolo elenca i pacchetti più promettenti e più popolari per dare un’idea della maturità di Flutter come piattaforma.

1) HTTP
2) flutter_slidable
3) Condivisione di Preferences
4) sqflite
5) url_launcher
6) video_player
7) crypto
8) carousel_slider
9) path
10) location


1 HTTP

URL: https://pub.dev/packages/http
Funziona su: iOS, Android, Web

Oggigiorno tutto è basato sul web, quindi una solida libreria HTTP è un must. Questo pacchetto Dart contiene una serie di funzioni e classi di alto livello che semplificano l’utilizzo delle risorse HTTP. È ben sviluppato e gestito attivamente dal team Dart. È in circolazione dal 2012, quindi dovrebbe essere solido come una roccia!
La libreria offre funzioni di alto livello che semplificano il lavoro con HTTP:

import 'package:http/http.dart' as http;

# Posting data
var url = 'https://example.com/whatsit/create';
var data = {'name': 'Jack', 'age': 38};

var response = await http.post(url, body: data);

print('Response status: ${response.statusCode}');
print('Response body: ${response.body}');

# A simple GET request
print(await http.read('https://example.com/foobar.txt'));

2 flutter_slidable

URL: https://pub.dev/packages/flutter_slidable
Funziona su: iOS, Android, Web

Il plug-in flutter_slidable aggiunge un widget di scorrimento ricco di funzionalità al vostro progetto. I cursori come questo sono spesso visti in elenchi scorrevoli. L’app Gmail è un esempio notevole, in cui gli elementi dell’elenco scorrevole offrono un significativo miglioramento della produttività.
Questo plugin è ricco di funzionalità e pronto per l’uso, ma anche altamente personalizzabile se necessario. Alcune delle caratteristiche elencate sono:

– Accetta elenchi di widget principali (sinistra / in alto) e secondari (destra / in basso) come azioni di diapositiva
– Può essere dismesso
– Quattro riquadri azione integrati
– Due widget di azione di diapositiva incorporati
– Animazione di eliminazione incorporata
– Crea facilmente layout e animazioni personalizzati
– Si chiude quando un’azione di scorrimento è stata toccata (sovrascrivibile)
– Si chiude quando lo scorrevole più vicino inizia a scorrere (sovrascrivibile)
– Opzione per disabilitare facilmente l’effetto diapositiva

3 Condivisione di Preferences

URL: https://pub.dev/packages/shared_preferences
Funziona su: iOS, Android, Web, Linux

Questo pacchetto racchiude le librerie di archiviazione persistente specifiche della piattaforma. È indentato per dati semplici, come le preferenze dell’utente, e utilizza:

– NSUserDefaults su iOS e macOS
– SharedPreferences su Android
– LocalStorage sui siti web
– Un file JSON sul file system locale per Linux

I dati possono essere conservati su disco in modo asincrono e non vi è alcuna garanzia che le scritture verranno mantenute su disco dopo la restituzione, quindi questo plug-in non è pensato per l’archiviazione di dati critici. Per quello si usa normalmente sqflite (vedi sotto).

4 sqflite

URL: https://pub.dev/packages/sqflite
Funziona su: iOS, Android, MacOS

Questo è il plugin SQLite per Flutter. Supporta iOS, Android e MacOS. Il Web non è supportato poiché non esiste un sistema di persistenza basato su SQL nei browser Web. Alcune delle sue caratteristiche sono:

– Supporto per transazioni e batch
– Gestione automatica delle versioni
– Aiutanti per inserire / interrogare / aggiornare / eliminare query

Le operazioni vengono eseguite in un thread in background su iOS e Android per impedire il blocco dell’interfaccia utente
Se hai bisogno di qualcosa di più dell’archiviazione dei dati di base (shared_preferences), non cercare oltre.

5 url_launcher

URL: https://pub.dev/packages/url_launcher
Funziona su: iOS, Android, Web

Questo plugin ti aiuta ad avviare un URL. Gli URL possono essere dei seguenti tipi:

HTTP: http://example.org e https://example.org
E-mail: mailto:
Numeri di telefono: tel:
Messaggio di testo SMS: sms:

L’utilizzo di base è molto semplice:

const url = 'https://flutter.dev';

if (await canLaunch(url)) {
  await launch(url);
} else {
  throw 'Could not launch $url';
}

6 video_player

URL: https://pub.dev/packages/video_player
Funziona su: iOS, Android, Web

Sono supportati molti formati, ma tutto dipende dalla piattaforma che stai utilizzando. Ad esempio, le librerie di supporto differiscono per iOS e Android. Inoltre, sul Web, i formati supportati dipendono dal browser che stai utilizzando.

Tieni presente che anche se si chiama video_player, questo plug-in può anche riprodurre l’audio. Poiché il plug-in è piuttosto maturo e ha raggiunto la stabilità dell’API, non è una cattiva idea usarlo per l’audio su alcune delle alternative.

Questo plugin può riprodurre video da un file locale (risorse) e un server remoto (ad esempio, un sito web).

7 crypto

Funziona su: tutte le piattaforme

Proveniente dallo stesso team di Dart, questo è un insieme di funzioni di hashing crittografiche implementate in puro Dart. Ciò significa che non hai bisogno di librerie esterne per farlo funzionare.
Sono supportati i seguenti algoritmi di hashing:

SHA-1
SHA-224
SHA-256
SHA-384
SHA-512
MD5
HMAC (ovvero HMAC-MD5, HMAC-SHA1, HMAC-SHA256)

Poiché questo non è uno strumento GUI ma semplicemente una libreria crittografica, funziona su tutte le piattaforme supportate.

URL: https://pub.dev/packages/carousel_slider
Funziona su: iOS, Android, Web

Un cursore a carosello fa parte di molte app e siti Web. Il plug-in carousel_slider offre un carosello eccellente e personalizzabile che funziona su più piattaforme.

Poiché il carousel accetta i widget come contenuto, puoi far scorrere qualsiasi cosa che possa essere un widget.
Per esempi dal vivo, puoi visitare questo sito Web, che utilizza Flutter web per dimostrare il plug-in.

Ecco un esempio di come creare un carosello nella tua app:

CarouselSlider(
  options: CarouselOptions(height: 400.0),
  items: [1,2,3,4,5].map((i) {
    return Builder(
      builder: (BuildContext context) {
        return Container(
          width: MediaQuery.of(context).size.width,
          margin: EdgeInsets.symmetric(horizontal: 5.0),
          decoration: BoxDecoration(
            color: Colors.amber
          ),
          child: Text('text $i', style: TextStyle(fontSize: 16.0),)
        );
      },
    );
  }).toList(),
)

Il carosello ha diverse opzioni configurabili, come:

– l’altezza e le proporzioni
– abilitare lo scorrimento infinito
– invertendo la giostra
– abilitare la riproduzione automatica con un intervallo configurabile, durata dell’animazione
– definire la direzione di scorrimento (verticale, orizzontale)

9 path

URL: https://pub.dev/packages/path
Funziona su: iOS, Android, Web

I percorsi sono sia facili che incredibilmente complessi perché differiscono da piattaforma a piattaforma. Per assicurarti di non introdurre bug o vulnerabilità di sicurezza nel tuo codice, usa sempre la libreria dei percorsi quando gestisci i percorsi. Per unire una directory e un file con il separatore di file per il sistema operativo corrente, utilizzare:

import 'package:path/path.dart' as p;
p.join('directory', 'file.txt');

10 location

URL: https://pub.dev/packages/location
Funziona su: iOS, Android, Web, MacOS

Uno dei grandi vantaggi dei telefoni è la loro mobilità combinata con la capacità di tracciare accuratamente la posizione. Questo ci ha già fornito molte applicazioni utili. Il plug-in di posizione per Flutter semplifica l’accesso alla posizione corrente. Fornisce callback quando la posizione è cambiata. Offre inoltre endpoint API per richiedere correttamente l’accesso alla posizione di un utente.

10 motivi per scegliere Flutter per lo sviluppo della vostra app

Le applicazioni multipiattaforma sono la soluzione che sempre piu’ frequentemente adottano le aziende che devono sviluppare una app, perché la realizzazione di app iOS e Android native separate è più costosa in termini sia di sviluppare che di manutenzione. Flutter offre un modo rapido per creare app visivamente accattivanti per sistemi operativi mobili, computer desktop e Web da una singola base di codice. Flutter viene utilizzato e promosso attivamente da Google ed è diventato molto popolare fra gli sviluppatori.

Ora, proviamo ad analizzare in dettaglio i punti di forza di questo framework di sviluppo software.


Sviluppo app multipiattaforma low-cost

La multipiattaforma ideale dovrebbe soddisfare due requisiti: fornire un’esperienza utente di alta qualità (animazioni fluide, elementi dell’interfaccia utente nativi senza rallentamenti) ed essere conveniente dal punto di vista dello sviluppo.

Il vantaggio di Flutter non è solo quello di sviluppare una sola applicazione invece di due ma anche quello di avere meno problemi nell’adattare la app a ciascuna delle piattaforme. La maggior parte dei framework ha queste caratteristiche ma soltanto nel contesto di applicazioni semplici.

I veri problemi iniziano quando un’applicazione diventa “invasa” dalle funzioni e l’app inevitabilmente si complica (cosa che accade per la maggior parte dei prodotti durante la fase di sviluppo).

 

Performances simili a quelle delle app native

Il fatto che una app flutter sia prodotta direttamente nel codice nativo fà si che non vi siano in seguito errori di interpretazione durante l’esecuzione.

Un’applicazione Flutter sarà in definitiva indistinguibile dall’app nativa, poiché non si basa su alcuna rappresentazione o interpretazione intermedia del codice, a differenza della maggior parte degli altri framework multipiattaforma.

Funziona non soltanto su mobile

Come accennato, la tecnologia è apparsa come Flutter 1.0 nel dicembre 2018. Da allora, Flutter ha dimostrato la sua capacità non solo di funzionare come un toolkit per piattaforme mobili ma anche per browser web e desktop. A maggio 2019, il suo team di sviluppo ha annunciato una versione di anteprima di Flutter per il Web che è stata inizialmente chiamata Hummingbird. Tuttavia, è stato successivamente ribattezzata Flutter Web.

Motore di rendering proprietario

Allo sviluppatore Flutter è concessa una assoluta libertà nella creazione di un’interfaccia utente indipendentemente dalla piattaforma. Questo perchè il framework utilizza il proprio motore di rendering per disegnare i widget.

Il problema di molte soluzioni multipiattaforma è che hanno lo stesso aspetto su iPhone e Android. Ma per quanto riguarda le aziende che devono utilizzare Material Design per Android e Human Interface per iOS? Per tali aziende, Flutter è la soluzione più adatta in quanto è dotato di pacchetti che contengono una serie di widget personalizzati per entrambi i sistemi operativi.

Semplicità nell’implementazione della logica

Flutter fornisce funzionalità del sistema operativo avanzate come coordinate GPS, raccolta dei dati dei sensori, gestione delle autorizzazioni, Bluetooth, credenziali e altre funzionalità in plug-in pronti per l’uso supportati da Google.

Se la app che progettate di sviluppare fa affidamento su una funzionalità a livello di sistema operativo non disponibile come plug-in, Flutter può stabilire la comunicazione tra il suo linguaggio di programmazione Dart e il codice nativo utilizzando i canali della piattaforma.

In poche parole si puo’ scrivere all’interno di un app Flutter anche in Java, Kotlin o Objective C.

Design accattivante

Due cose potenti furono originariamente poste alla base di Flutter: un eccellente linguaggio di programmazione (Dart) e un motore di rendering veloce e ad alte prestazioni (Skia). Tale scelta è stata una soluzione ben ponderata che salva gli utenti da ulteriori lunghe ricerche.

Il risultato è un’eccellente piattaforma che aiuta gli sviluppatori di tutti i livelli a creare applicazioni utilizzando modelli di progettazione e best practice appropriati. Si possono dimenticare le contraddizioni agli standard o i difetti tecnici causati dalle imperfezioni del linguaggio di programmazione. Flutter fornisce widget belli e personalizzabili che rendono le app Flutter fantastiche.

Flutter usa nativamente Firebase come back-end

Si possono utilizzare praticamente tutti i vantaggi di Firebase nello sviluppo di app Flutter, come si farebbe con uno sviluppo nativo. Inoltre, Flutter consente la creazione di app reattive e i plug-in Firebase offrono flussi reattivi per lavorare con i dati. Ciò consentirà di integrare rapidamente determinate soluzioni nelle applicazioni Flutter.

Flutter è basato su Dart

Nello sviluppo di Flutter, viene utilizzato il linguaggio di programmazione Dart. Anche Dart è uno dei linguaggi di programmazione di Google creato nell’ottobre 2011 ed è migliorato notevolmente negli ultimi anni. Dart è tipizzato staticamente e consente di scrivere un codice molto più strutturato, il che significa che si possono creare applicazioni e strutture gerarchiche molto complesse.

Il linguaggio ha una sintassi pulita e incredibilmente potente. Ciò fornisce le condizioni ideali per creare un’architettura e un design chiari per qualsiasi applicazione. Vale anche la pena ricordare che Dart garantisce coerenza di lavoro tra i programmatori, durata, bassa manutenzione e standard comuni. Molto più di quanto la maggior parte degli altri framework per lo sviluppo multipiattaforma possa offrire. Per coloro che hanno già lavorato con linguaggi popolari come C #, Java e TypeScript, sarà facile passare a Dart e iniziare a usarlo subito.

Un kit di widgets customizzabile

I widget sono i blocchi di base utilizzati per costruire un’interfaccia utente di un’applicazione Flutter. La sua stratificazione facilita la creazione di applicazioni di qualsiasi complessità. È possibile utilizzare widget già pronti da Material-UI o implementare componenti specifici basati su widget di base. Con Flutter, è anche possibile lavorare in modo flessibile con l’animazione e l’elaborazione dei gesti. Pertanto, si puo’ combinare un lavoro rapido con widget di alto livello e avere ancora la possibilità di aggiungere / ridefinire livelli più profondi.

Hot reload

La funzione hot reload aiuta a sperimentare rapidamente e facilmente, creare interfacce utente, aggiungere funzionalità e correggere bug più velocemente. Stimola il processo di sviluppo fornendo a uno sviluppatore un record del codice sorgente direttamente all’interno dell’applicazione funzionante. Aiuta a riflettere sulle modifiche apportate al codice in meno di 2-3 secondi e senza ripristinare lo stato dell’applicazione.

Pertanto, Hot Reload consente di monitorare rapidamente lo sviluppo dell’applicazione. A seconda della complessità e della natura del progetto, è possibile risparmiare dal 20 al 50% in termini di tempo, che può essere speso per lo sviluppo di altre funzioni utili.

Come potenziare la ricerca su WordPress con Elasticsearch

In alcuni casi avere un efficente motore di ricerca interno al sito puo’ essere fondamentale per aumentare l’engagement di un utente. Sopratutto gli e-commerce, oppure i siti con elevato volume di contenuti, rischiano di perdere l’utente qualora il tempo di ricerca di un determinato prodotto o soggetto si protragga per troppo tempo. L’utente non è per sua natura paziente, e pretende risposte precise ed immediate.

In questo articolo cercheremo di riassumere alcuni concetti fondamentali riguardanti il motore di ricerca di WordPress (e quindi di WooCommerce) ed una soluzione per migliorare notevolmente le prestazioni di ricerca utilizzando Elasticsearch, un motore di ricerca distribuito per tutti i tipi di dati basato su Apache Lucene.

Le nuove versioni di Elasticsearch inoltre migliorano notevolmente il lavoro sulle intenzioni di ricerca grazie a componenti di intelligenza artificiale.

1) La ricerca full-text su MySql
2) La ricerca su WordPress e Woocommerce
3) Installazione ambiente di test
4) Abilitazione del log delle slow query su MySql
5) Analisi di una query di ricerca su WordPress
6) La stessa query eseguita su Elasticsearch
7) Conclusioni


1. La ricerca full-text su MySql

La ricerca “full-text” (FTS) è la ricerca classica che facciamo, su Google o su qualsiasi altro motore di ricerca quando ricerchiamo una determinata parola o una frase. Questo tipo di ricerca è una tecnica per trovare documenti che possono non corrispondere esattamente ai criteri di ricerca.

Possiamo per esempio cercare le parole “Sole e Mare” e la FTS potrà restituire documenti che contengono sia esclusivamente ciascuna delle due sinole parole, “Sole” o “Mare”, oppure risultati che contengono entrambe le parole sia nellordine esatto che in un altro ordine, per esempio “Sole e Mare” oppure “Mare e Sole”.

Parlando tecnicamente, MySql supporta le ricerche di testo parziali utilizzando l’operatore “LIKE” e le regular expressions. Questo tipo di ricerca ha pero’ diversi limiti man mano che aumentano le dimesioni del campo di testo in cui la ricerca viene fatta, oppure aumenta il numero dei records nella tabella in cui si cerca.

I limiti principali sono:
1) una scarsa performance, perchè MySql deve cercare i termini in tutti i campi della tabella prima di restituire i risultati
2) una scarsa flessibilità nella ricerca, in quanto diventa difficile trovare risultati che escludano uno dei termini della ricerca (per esempio “Mare” ma non “Sole”)
3) l’impossibilità di avere un punteggio di rilevanza nei risultati ottenuti

A causa di queste limitazioni, MySql, a partire dalla versione 5.6 ha introdotto un indice apposito per le ricerche full-text.

2. La ricerca su WordPress e Woocommerce

Sfortunatamente la struttura del database MySql che arriva con l’installer di wordpress non utilizza le nuove funzionalità introdotte in MySQL. Nella tabella ‘wp_posts’ per esempio possiamo notare come l’indicizzazione usata sia quella standard, ossia la ‘BTREE’.

Senza stare ad addentrarsi nelle dinamiche del funzionamento di questo tipo di indice, si puo’ dire semplicemente che tale indice permette di effettuare delle ricerche con operatori di uguaglianza (= oppure <=>),operatori che diano risultati all’interno di un range (>, <, >=, <=, BETWEEN), oppure l’operatore LIKE.

Adesso viene pero’ il bello perchè andremo a strutturare un ambiente per misurare l’effettivo carico delle query di ricerca su WordPress ed esaminarne la struttura.

3. Installazione ambiente di test

Per poter effettuare il nostro benchmarch e capire quale sia veramente il costo delle query di ricerca su WordPress ed avere un termine di paragone con una query eseguita su Elasticsearch abbiamo:

1) Installato un’istanza di WordPress
Per eseguire questo passaggio in velocità abbiamo approfittato delle istanze ready to run sul marketplace di Digital Ocean. Per dare un po’ di brillantezza alla ricerca abbiamo optato per una configurazione con 2 CPU dedicate e 8GB di memoria. Se ce ne fosse bisogno potrete rinfrescare la vostra conoscenza leggendo l’articolo “Cos’è e come finziona WordPress

2) Installato un’istanza di Elasticsearch
Utilizzando un container Docker su Amazon AWS, in questo caso la potenza dell’istanza è minima: una T2.small con 1CPU e 2GB di ram

3) Inserito una serie di dati dummy per poter fare ricerche full-text su un database consistente

Per utilizzare le api-rest di WordPress in maniera veloce, ma non sicura, abbiamo installato un plugin che permetta un’autenticazione di tipo Basic. Questa pratica è ovvimante sconsigliata all’utilizzo in produzione.

Lato Elasticsearch abbiamo creato un index che riporoducesse i campi full-text del database MySql di WordPress in modo da poter effettuare parallelamente la stessa ricerca sui due database.

Utilizzando il servizio api Loripsum abbiamo inserito 11.000 articoli sul nostro WordPress con titoli e contenuti random.

Questo il sorgente del file che ha effettuato il caricamento dei dati:

function wp_insert($title,$content){
$username = 'xxxxxxx';
$password = 'yyyyyyyyyyy';
$rest_api_url = "https://my.test.site/wp-json/wp/v2/posts";

$data_string = json_encode([
    'title'    => $title,
    'content'  => $content,
    'status'   => 'publish',
]);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $rest_api_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);

curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Content-Length: ' . strlen($data_string),
    'Authorization: Basic ' . base64_encode($username . ':' . $password),
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$result = curl_exec($ch);

curl_close($ch);
return json_decode($result);
}
function dbg($s){
	echo "\n";
	print_r($s);
	echo "\n";
}
function es_insert($title,$content,$link){
	$topost = array(
		"link" => $link,
		"title" => $title,
		"description" => $content,
		"pubdate" => date("Y-m-d H:i:s"),
		"author" => "Admin"
	);
	$data = json_encode($topost,JSON_PRETTY_PRINT);
	$ch = curl_init();

	curl_setopt($ch, CURLOPT_URL, 'elasticearch.host.ip:9200/post/_doc/?pretty');
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

	$headers = array();
	$headers[] = 'Content-Type: application/json';
	curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

	$result = curl_exec($ch);
	if (curl_errno($ch)) {
	    echo 'Error:' . curl_error($ch);
	}
	curl_close($ch);
	return json_decode($result);
}

function li_get($wich){

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $wich);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($ch);
        curl_close($ch);
        return $output;      
}


for($i=0;$i<10000;$i++){ $title = li_get("https://loripsum.net/api/1/short"); $incipit = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; $title = str_replace($incipit, "", $title); $title = substr(trim($title),0,100); $title = strip_tags($title); $title = preg_replace('/\[.*\]/', '', $title); dbg($title); if($title == "") die('aaaaargh'); $content = li_get("https://loripsum.net/api/20/verylong/headers"); $wp = wp_insert($title,$content); if(isset($wp->link)){
		dbg($wp->link);
		$uno = strip_tags($content);
		$testo = preg_replace('/\[.*\]/', '', $uno);
		
		$es = es_insert($title,$testo,$wp->link);
		dbg($es);
	}
}

Proviamo a misurare il volume del database che abbiamo creato:

mysql> SELECT
    ->   TABLE_NAME AS `Table`,
    ->   ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024) AS `Size (MB)`
    -> FROM
    ->   information_schema.TABLES
    -> WHERE
    ->     TABLE_SCHEMA = "wordpress"
    ->   AND
    ->     TABLE_NAME = "wp_posts"
    -> ORDER BY
    ->   (DATA_LENGTH + INDEX_LENGTH)
    -> DESC;
+----------+-----------+
| Table    | Size (MB) |
+----------+-----------+
| wp_posts |       366 |
+----------+-----------+
1 row in set (0.01 sec)

Sono 366 Mb, nemmeno tanti…. 🙂

4. Abilitazione del log delle slow query su MySql

Per poter misurare correttamente il tempo di esecuzione delle query di ricerca di WordPress abbiamo ancora bisogno di istruire MySql affinchè scriva in un file di log i dettagli delle query la cui esecuzione superi un certo periodo di tempo.

Per fare questo andiamo ad aggiungere alcune istruzioni nel file di configurazione di MySql. Apriamo con un editor il file di configurazione:

nano /etc/mysql/mysql.conf.d/mysqld.cnf

ed aggiungiamo queste linee:

 slow_query_log         = 1
 slow_query_log_file    = /var/log/mysql/slow.log
 long_query_time = 1
 log-queries-not-using-indexes = ON

Poi creiamo il file di log e lo rendiamo scrivibile (quest’ultima istruzione è da evitare in produzione ma bisogna attribuire all’utente mysql la proprietà del file):

touch /var/log/mysql/slow.log
chmod 777 /var/log/mysql/slow.log

Ora facciamo ripartire MySql con la nuova configurazione:

/etc/init.d/mysql restart

5. Analisi di una query di ricerca su WordPress

Abbiamo ora tutti gli elementi per poter testare una query di ricerca su WordPress. Abbiamo 11.000 post riempiti di Lorem Ipsum, possiamo scegliere 2 termini a caso che sappiamo presenti in un articolo, inserirli nella form di ricerca e vedere come si comporta WordPress.

La ricerca che io ho scelto di fare è sui termini “Cicero cognoscere”. Eseguo la ricerca. Vado a leggere nel log delle slow query cosa è successo.

Questa è la query che WordPress ha fatto:

SELECT SQL_CALC_FOUND_ROWS  wp_posts.ID FROM wp_posts  WHERE 1=1  
AND (((wp_posts.post_title LIKE '%Cicero%') 
OR (wp_posts.post_excerpt LIKE '%Cicero%') 
OR (wp_posts.post_content LIKE '%Cicero%')) 
AND ((wp_posts.post_title LIKE '%cognoscere%') 
OR (wp_posts.post_excerpt LIKE '%cognoscere%') 
OR (wp_posts.post_content LIKE '%cognoscere%')))  
AND wp_posts.post_type IN ('post', 'page', 'attachment') 
AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private')  
ORDER BY (CASE WHEN wp_posts.post_title LIKE '%Cicero cognoscere%' THEN 1 WHEN wp_posts.post_title LIKE '%Cicero%' AND wp_posts.post_title LIKE '%cognoscere%' THEN 2 WHEN wp_posts.post_title LIKE '%Cicero%' OR wp_posts.post_title LIKE '%cognoscere%' THEN 3 WHEN wp_posts.post_excerpt LIKE '%Cicero cognoscere%' THEN 4 WHEN wp_posts.post_content LIKE '%Cicero cognoscere%' THEN 5 ELSE 6 END), wp_posts.post_date DESC LIMIT 0, 10;

Ossia, WordPress ha cercato singolarmente le due parole richieste nei campi titolo, excerpt e content della tabella posts ove il tipo di post fosse un artcolo, una pagina o un attachment (ossia un immagine).

Li ha poi ordinati come importanza a seconda che nel titolo vi fosse la stringa completa o uno dei due termini e con lo stesso criterio a seguire e disponendoli a seconda della data di creazione in maniera discendente ed in numero di 10.

E poi:

# Query_time: 3.922342  Lock_time: 0.000138 Rows_sent: 10  Rows_examined: 12734

L’effettuazione della query ha preso 3,9 secondi per cercare in 12734 records.

Considerando la potenza della macchina ed il fatto che questa query fosse l’unica attività in corso in quel momento, la prestazione non sembra in effetti molto brillante. Altri test fatti su macchine meno performanti hanno dato, ovviamente, risultati decisamente peggiori.

Ma sopratutto il criterio lascia perplessi, in quanto come si puo’ osservare dagli id dei post ottenuti in risposta alla query

+-------+
| ID    |
+-------+
| 11465 |
| 11459 |
| 11452 |
| 11451 |
| 11443 |
| 11442 |
| 11437 |
| 11434 |
| 11432 |
| 11416 |
+-------+

sono stati selezionati esclusivamente post molto recenti, il che non è una garanzia per l’ottimizzazione del risultato di ricerca.

E’ necessario anche sottolineare il fatto che tutti i plugin che esistono per implementare diversi modi di ricerca per Worpress o WooCommerce possono migliorare il dettaglio del risultato ma non certo la prestazione che anzi, quasi sempre, peggiorano.

6. La stessa query eseguita su Elasticsearch

Andiamo ora ad implementare la ricerca verso Elasticsearch che, come abbiamo detto, risiede su un’altra macchina, non molto performante, su un altro cloud, le due macchine sono comunque nella stessa regione US-EAST.

Per amor di brevità prenderemo una scorciatoia, ovvio che questa implementazione dovrebbe essere fatta diversamente. Da notare che esistono dei plugin per integrare WordPress con Elasticsearch, ma, ahimè, non funzionano 😉

Creiamo quindi una pagina con slug /elasticsearch-search

Creiamo poi un template di pagina, lo chiamiamo “Elastic Page Search”. Dentro il template creiamo una form che abbia un input di testo per la rcerca e la action allo slug della nostra pagina. Inseriamo poi, dopo la form, questo codice:

if(isset($_POST['string']) && $_POST['string'] != ""){
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'my.elasticsearch.ip:9200/post/_search?pretty');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "\n{\n  \"query\": {\n    \"multi_match\" : {\n      \"query\":    \"".$_POST['string']."\", \n      \"fields\": [ \"title^2\", \"description\" ] \n    }\n  },\n   \"fields\": [\"title\", \"link\"],\n   \"_source\": false\n}\n");

$headers = array();
$headers[] = 'Content-Type: application/json';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$result = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
curl_close($ch);
}

$res = json_decode($result);
print_r($result);
			

Analizziamo in particolare il JSON con cui andiamo ad interrogare Elasticsearch:

{
  "query": {
    "multi_match" : {
      "query":    "Cicero cognoscere", 
      "fields": [ "title^2", "description" ] 
    }
  },
   "fields": ["title", "link"],
   "_source": false
}

Praticamente, noi cerchiamo la nostra frase nel titolo e nella descrizione del post, specificando che qual’ora venisse ritrovato nel titolo uno dei termini, questo verrebbe valutato doppio nell’attribuzione del ranking di Elasticsearch, e ci facciamo restituire solo il titolo e lo slug dell’articolo. Otteniamo questi risultati:

{
  "took" : 846,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 876,
      "relation" : "eq"
    },
    "max_score" : 3.5842853,
    "hits" : [
      {
        "_index" : "post",
        "_type" : "_doc",
        "_id" : "KIuDyXYBaPVcgdaTjmHU",
        "_score" : 3.5842853,
        "fields" : {
          "link" : [
            "https://awswp.pipozzi.site/quae-diligentissime-contra-aristonem-dicuntur-a-chryippo-scrupulum-inquam-abeunti-contemnit/"
          ],
          "title" : [
            " Quae diligentissime contra Aristonem dicuntur a Chryippo. Scrupulum, inquam, abeunti; Contemnit "
          ]
        }
      },
      {
        "_index" : "post",
        "_type" : "_doc",
        "_id" : "8YuJyXYBaPVcgdaTLmEi",
        "_score" : 3.572124,
        "fields" : {
          "link" : [
            "https://awswp.pipozzi.site/post-enim-chrysippum-eum-non-sane-est-disputatum-duo-reges-constructio-interrete-nihil-illinc/"
          ],
          "title" : [
            " Post enim Chrysippum eum non sane est disputatum. Duo Reges: constructio interrete. Nihil illinc"
          ]
        }
      },

....

Traducendo i messaggi piu’ importanti che Elasticsearch ci manda, otteniamo che:
1) la query è stata eseguita in 0,846 secondi (“took” : 846)
2) sono stati trovati 876 documenti contenenti la nostra chiave (hits->total->value = 876)
3) Elasticsearch ci ha restituito 10 risultati ( avremmo potuto scegliere il numero) ordinati secondo il punteggio ( “_score” : 3.572124 ) che lui ha calcolato utilizzando il suo sofisticato sistema di indicizzazione.

7. Conclusioni

Possiamo concludere il nostro tutorial affermando che in tutte le web applications gestite con WordPress, e quindi con WooCommerce, in cui venga gestito un grande volume di dati, soppiantare il sistema di ricerca nativo con un sistema parallelo basato su Elasticsearch porta indiscutibilmente una serie di vantaggi fondamentali:

1) Esecuzione della ricerca con velocità almeno 4 volte superiore
2) Maggiore precisione nella ricerca
3) Maggiore consistenza dei risultati ottenuti grazie al sistema di ranking di Elasticsearch