{"id":27497,"date":"2020-01-22T00:00:00","date_gmt":"2020-01-21T23:00:00","guid":{"rendered":"https:\/\/blexin.com\/?p=27497"},"modified":"2021-01-13T09:40:16","modified_gmt":"2021-01-13T08:40:16","slug":"integrare-elasticsearch-in-asp-net-core","status":"publish","type":"post","link":"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/","title":{"rendered":"Integrare ElasticSearch in ASP.NET Core"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"608\" data-attachment-id=\"27499\" data-permalink=\"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/attachment\/image00-12\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image00-12.png?fit=1024%2C608&amp;ssl=1\" data-orig-size=\"1024,608\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"image00-12\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image00-12.png?fit=1024%2C608&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image00-12.png?resize=1024%2C608&#038;ssl=1\" alt=\"\" class=\"wp-image-27499\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image00-12.png 1024w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image00-12-980x582.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image00-12-480x285.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Vi sar\u00e0 sicuramente capitata la richiesta di aggiungere alla vostra applicazione delle funzionalit\u00e0 di ricerca avanzata e, in particolare, una ricerca full-text&nbsp;stile Google.<br>Durante lo sviluppo di un e-commerce, ci \u00e8 stato richiesto di permettere agli utenti del sito di poter fare ricerche avanzate sui prodotti, in modo che potessero trovare, in modo efficiente e completo, ci\u00f2 che cercavano.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Abbiamo tentato l\u2019implementazione di ricerche custom, basate sulla ricerca dell\u2019occorrenza puntuale di una determinata stringa su tutti i campi di un oggetto e, per ottimizzare i tempi, abbiamo provato ad aggiungere uno strato di cache nella chiamata in modo da evitare di stressare troppo il DB, ma il tutto non ci sembrava molto efficiente. Abbiamo quindi cercato sul mercato prodotti che potessero essere affini alle nostre esigenze, e, dopo un\u2019approfondita analisi, abbiamo scelto di usare ElasticSearch: un motore di ricerca, distribuito, facilmente adattabile e che gestisce ricerche e analisi anche su protocollo REST, facilitando l\u2019estrapolazione e la trasformazione dei dati.<br>Nello specifico, stiamo parlando di un motore di ricerca full text open source basato su Apache Lucene, con cui gestisce l\u2019indicizzazione dei documenti e la ricerca. Cerchiamo di capire quali sono i concetti di base.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">ElasticSearch conserva i dati in uno o pi\u00f9&nbsp;<strong>indici<\/strong>. L\u2019indice di ES \u00e8 un concetto abbastanza simile a quello dei database SQL, ovvero viene utilizzato per salvare e leggere documenti.<br>Il&nbsp;<strong>Documento<\/strong>&nbsp;\u00e8 l\u2019entit\u00e0 principale del mondo ElasticSearch. Consiste in un insieme di campi con nomi e uno o pi\u00f9 valori. Ogni documento pu\u00f2 avere un insieme di campi e non c\u2019\u00e8 uno schema o una struttura definita per esso. Da un punto di vista formale, \u00e8 un oggetto JSON.<br>Tutti i documenti, prima di essere salvati, vengono analizzati. Questo processo di analisi &#8211; chiamato&nbsp;<strong>mapping&nbsp;<\/strong>&#8211; avviene tramite operazioni di pulizia del contenuto dei documenti (ad esempio, eliminazione di tag HTML) e tokenizzazione di essi, ovvero il contenuto viene splittato in token.<br>Ogni documento in ElasticSearch ha un&nbsp;<strong>tipo&nbsp;<\/strong>definito. Ci\u00f2 consente di salvare vari tipi di documento in uno stesso indice ed avere mapping diversi per tipi diversi.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Un singola istanza di un server ElasticSearch \u00e8 chiamata&nbsp;<strong>Nodo<\/strong>. Un singolo nodo pu\u00f2 essere sufficiente per la maggior parte dei casi d\u2019uso, ma quando bisogna gestire guasti oppure la mole di dati cresce \u00e8 possibile utilizzare un&nbsp;<strong>Cluster<\/strong>&nbsp;multi-nodo. \u00c8 possibile configurare un cluster in modo che, anche se alcuni nodi non sono disponibili, le funzionalit\u00e0 di ricerca e gestione sono comunque utilizzabili.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Per consentire il corretto funzionamento dei cluster, i dati vengono diffusi su diversi indici fissi di Apache Lucene. Questi indici sono chiamati&nbsp;<strong>Shard<\/strong>, e il processo di diffusione \u00e8 chiamato&nbsp;<strong>sharding<\/strong>. ElasticSearch gestisce automaticamente lo sharding e l\u2019utente finale vede tutti gli indici creati come un unico grande indice<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Per la sola fase di lettura, \u00e8 possibile utilizzare una&nbsp;<strong>Replica<\/strong>, che consente di sgravare il carico su un singolo nodo che non ha la capacit\u00e0 di gestire tutte le richieste e, inoltre, consente una maggiore sicurezza sui dato poich\u00e9, se si perdono dati dallo shard originale, \u00e8 possibile recuperarli dalla replica. ElasticSearch colleziona varie informazioni circa lo stato dei cluster, impostazioni degli indici etc., e li scrive nei&nbsp;<strong>Gateway<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dal punto di vista architetturale, ElasticSearch \u00e8 basato su alcuni semplici concetti chiave:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Impostazioni e valori di configurazione di default tali che l\u2019utente, una volta installato ElasticSearch, possa iniziare ad utilizzarlo subito senza aver necessit\u00e0 di ulteriori configurazioni;<\/li><li>Lavora subito in maniera distribuita. I nodi diventano automaticamente parte di un cluster e, durante la fase di setup, cerca automaticamente di unirsi a quest\u2019ultimo;<\/li><li>Architettura P2P senza SPOF (single point of failure). I nodi si connettono automaticamente ad altre macchine del cluster per scambio di dati e monitoraggio incrociato;<\/li><li>Facilmente scalabile, sia in termini di capacit\u00e0 che di mole di dati, tramite l\u2019aggiunta di nuovi nodi al cluster;<\/li><li>Nessuna restrizione sull\u2019organizzazione dei dati nell\u2019index. Ci\u00f2 consente agli utenti di modificare il modello dei dati e avere praticamente zero impatti nelle ricerche;<\/li><li>Ricerca e versionamento NRT (Near Real Time). Per la natura distribuita di ElasticSearch, \u00e8 impossibile evitare ritardi e differenze tra dati locati su nodi differenti, per cui sono forniti meccanismi come il versionamento.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Quando un nodo di ElasticSearch si avvia, usa la modalit\u00e0 multicast (o unicast, se configurata) per cercare altri nodi sullo stesso cluster e si connette ad essi.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"500\" data-attachment-id=\"27502\" data-permalink=\"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/attachment\/image01-9\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image01-9.png?fit=2321%2C1134&amp;ssl=1\" data-orig-size=\"2321,1134\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"image01-9\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image01-9.png?fit=1024%2C500&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image01-9.png?resize=1024%2C500&#038;ssl=1\" alt=\"\" class=\"wp-image-27502\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image01-9-980x479.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image01-9-480x235.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">In un cluster, uno dei nodi \u00e8 scelto come nodo master, che detiene la responsabilit\u00e0 di gestire lo stato del cluster e il processo di assegnazione degli shard ai nodi. Il nodo master legge lo stato del cluster e, se necessario, inizia una fase di recupero in cui individua quali shard sono disponibili e ne assegna uno come primario. In questo modo il cluster risulta funzionante pur non avendo tutte le risorse a disposizione. Successivamente il nodo master ricerca shard duplicati e li gestisce come repliche.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durante il funzionamento standard, il nodo master monitora i nodi disponibili e controlla se sono tutti funzionanti. Se uno di essi non \u00e8 disponibile per un intervallo di tempo configurato, il nodo viene segnalato come rotto e si avvia il processo di gestione del guasto.<br>L\u2019attivit\u00e0 principale del processo di gestione del guasto \u00e8 il bilanciamento del cluster e degli shard del nodo rotto, e l\u2019assegnazione di un nuovo nodo come responsabile di questi shard.<br>Per ogni shard primario perso, sar\u00e0 definito un nuovo shard primario scelto tra le repliche disponibili.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"753\" data-attachment-id=\"27506\" data-permalink=\"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/attachment\/image02-8\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image02-8.png?fit=1691%2C1243&amp;ssl=1\" data-orig-size=\"1691,1243\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"image02-8\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image02-8.png?fit=1024%2C753&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image02-8.png?resize=1024%2C753&#038;ssl=1\" alt=\"\" class=\"wp-image-27506\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image02-8-980x720.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image02-8-480x353.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Come gi\u00e0 detto, ElasticSearch mette a disposizione delle API REST che sono facilmente integrabili con qualsiasi sistema che pu\u00f2 inviare richieste HTTP. Le richieste sono inviate tramite URL definite, il cui body \u00e8 in formato JSON, cos\u00ec come le risposte.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">L\u2019indicizzazione dei dati pu\u00f2 essere fatta in quattro modi:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Index API: consente di inviare un documento a un indice definito;<\/li><li>Bulk API: consente l\u2019invio multiplo tramite protocollo HTTP;<\/li><li>UDP bulk API: consente l\u2019invio multiplo su qualsiasi protocollo (pi\u00f9 veloce della Bulk API, ma meno affidabile);<\/li><li>Plugin: vengono eseguiti sul nodo, recuperano dati da sistemi esterni.<\/li><\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">\u00c8 fondamentale ricordare che l\u2019indicizzazione avviene solo sullo shard primario e non sulla sua replica, per cui, se la richiesta di indicizzazione viene inviata a un nodo che non ha uno shard corretto o ne contiene una replica, viene inoltrata allo shard principale.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"782\" data-attachment-id=\"27508\" data-permalink=\"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/attachment\/image03-7\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image03-7.png?fit=2042%2C1560&amp;ssl=1\" data-orig-size=\"2042,1560\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"image03-7\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image03-7.png?fit=1024%2C782&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image03-7.png?resize=1024%2C782&#038;ssl=1\" alt=\"\" class=\"wp-image-27508\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image03-7-980x749.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image03-7-480x367.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">La ricerca avviene tramite la&nbsp;<strong>Query API<\/strong>. Utilizzando un linguaggio basato su JSON per costruire query complesse, chiamato&nbsp;<strong>Query DSL<\/strong>, \u00e8 possibile:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>usare varie tipi di query, incluse query semplici, frasi, intervalli, booleani, coordinate spaziali e altre query;<\/li><li>costruire query complesse combinando query semplici;<\/li><li>filtrare documenti, eliminando quelli che non corrispondono ai criteri selezionati senza influenzare lo scoring;<\/li><li>trovare documenti simili ad un dato documento;<\/li><li>trovare suggerimenti e correzioni per una data frase;<\/li><li>trovare query che corrispondono a un dato documento.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">La ricerca non \u00e8 comunque un processo semplice ad una fase ma, in generale \u00e8 possibile suddividerla in due fasi: la fase di&nbsp;<strong>scatter<\/strong>, in cui si interrogano tutti gli shard rilevanti sull\u2019indice, e la fase di&nbsp;<strong>gather<\/strong>, in cui si elaborano e ordinano i risultati della fase di scatter.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"780\" data-attachment-id=\"27511\" data-permalink=\"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/attachment\/image04-8\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image04-8.png?fit=1883%2C1434&amp;ssl=1\" data-orig-size=\"1883,1434\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"image04-8\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image04-8.png?fit=1024%2C780&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image04-8.png?resize=1024%2C780&#038;ssl=1\" alt=\"\" class=\"wp-image-27511\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image04-8-980x746.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image04-8-480x366.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Sporchiamoci le mani<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">ES offre diverse modalit\u00e0 di utilizzo, sia locali che in cloud. Per installare ES su una macchina Windows, \u00e8 necessario che sia presente la versione corretta della Java Virtual Machine (<a href=\"https:\/\/www.elastic.co\/support\/matrix#matrix_jvm\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.elastic.co\/support\/matrix#matrix_jvm<\/a>), poi si pu\u00f2 scaricare il file zip dalla pagina dei download (<a href=\"https:\/\/www.elastic.co\/downloads\/elasticsearch\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.elastic.co\/downloads\/elasticsearch<\/a>) ed estrarlo in una cartella sul disco, nel nostro caso&nbsp;<em>C:\\Elasticsearch<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Per eseguirlo basta lanciare il file&nbsp;<em>C:\\Elasticsearch\\bin\\elasticsearch.bat<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Nel caso si desideri utilizzare ElasticSearch come servizio, in modo da poterlo avviare o stoppare tramite i servizi di Windows, \u00e8 necessario aggiungere una riga al file&nbsp;<em>C:\\Elasticsearch\\config\\jvm.options<\/em>, che, nel caso dei sistemi a 32 bit, \u00e8&nbsp;<em>-Xss320k<\/em>, mentre per i 64 \u00e8&nbsp;<em>-Xss1m<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dopo aver apportato questa modifica, da prompt dei comandi o da powershell si pu\u00f2 eseguire il file&nbsp;<em>C:\\Elasticsearch\\bin\\elasticsearch-service.bat<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I comandi disponibili sono&nbsp;<em>install<\/em>,&nbsp;<em>remove<\/em>,&nbsp;<em>start<\/em>,&nbsp;<em>stop<\/em>&nbsp;e&nbsp;<em>manager<\/em>.&nbsp;Per installare il servizio, digitiamo naturalmente:&nbsp;<em>C:\\Elasticsearch\\bin\\elasticsearch-service.bat install<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Per gestire il servizio, digitiamo&nbsp;<em>C:\\Elasticsearch\\bin\\elasticsearch-service.bat manager&nbsp;<\/em>che ci apre Elastic Service Manager, una GUI che consente di personalizzare impostazioni relative al servizio e gestire lo stato dello stesso.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dopo l\u2019avvio dell\u2019istanza di ElasticSearch, il nome di default del cluster (cluster.name nelle impostazioni) \u00e8&nbsp;<strong>elasticsearch<\/strong>, e il nome del nodo (node.name) \u00e8 uguale all\u2019hostname del proprio PC. Nel caso si pianifichi di proseguire nell\u2019utilizzo di questo cluster o aggiungere pi\u00f9 nodi, \u00e8 una buona idea quella di cambiare questi valori di default con dei propri modificandoli nel file&nbsp;<em>elasticsearch.yml<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Possiamo verificare la corretta esecuzione di ElasticSearch da browser, tramite la pagina <a href=\"http:\/\/localhost:9200\/\" rel=\"nofollow\">http:\/\/localhost:9200\/<\/a>, in cui otteniamo un risultato simile:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"462\" height=\"328\" data-attachment-id=\"27513\" data-permalink=\"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/attachment\/image05-9\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image05-9.png?fit=462%2C328&amp;ssl=1\" data-orig-size=\"462,328\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"image05-9\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image05-9.png?fit=462%2C328&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image05-9.png?resize=462%2C328&#038;ssl=1\" alt=\"\" class=\"wp-image-27513\" srcset=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image05-9.png?w=462&amp;ssl=1 462w, https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image05-9.png?resize=300%2C213&amp;ssl=1 300w, https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image05-9.png?resize=400%2C284&amp;ssl=1 400w\" sizes=\"auto, (max-width: 462px) 100vw, 462px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Per implementare la nostra soluzione, basata su .NET Core, abbiamo utilizzato il pacchetto&nbsp;<strong>NEST<\/strong>, che possiamo installare tramite il comando:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>dotnet add package NEST<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">NEST ci consente di utilizzare nativamente tutte le funzionalit\u00e0 di ElasticSearch, sia nell\u2019indicizzazione e la ricerca dei documenti, sia nell\u2019amministrazione di nodi e shard, e ci astrae totalmente dal livello di API della piattaforma.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Per gestire il plugin NEST, abbiamo creato la classe ElasticsearchExtensions:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic static class ElasticsearchExtensions\n{\n\u00a0\u00a0\u00a0\u00a0public static void AddElasticsearch(this IServiceCollection services, IConfiguration configuration)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var url = configuration&#x5B;&quot;elasticsearch:url&quot;];\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var defaultIndex = configuration&#x5B;&quot;elasticsearch:index&quot;];\n\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var settings = new ConnectionSettings(new Uri(url))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.DefaultIndex(defaultIndex);\n\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0AddDefaultMappings(settings);\n\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var client = new ElasticClient(settings);\n\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0services.AddSingleton(client);\n\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0CreateIndex(client, defaultIndex);\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0\u00a0\u00a0private static void AddDefaultMappings(ConnectionSettings settings)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0settings\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DefaultMappingFor&lt;Product&gt;(m =&gt; m\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Ignore(p =&gt; p.Price)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Ignore(p =&gt; p.Quantity)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Ignore(p =&gt; p.Rating)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0);\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0\u00a0\u00a0private static void CreateIndex(IElasticClient client, string indexName)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var createIndexResponse = client.Indices.Create(indexName,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0index =&gt; index.Map&lt;Product&gt;(x =&gt; x.AutoMap())\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0);\n\u00a0\u00a0\u00a0\u00a0}\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">in cui sono contenute le configurazioni e i mapping degli oggetti, nel nostro caso la classe Product, su cui abbiamo deciso di ignorare, in fase di indicizzazione, il prezzo, la quantit\u00e0 e il rating.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Questa classe viene richiamata in Startup.cs tramite l\u2019istruzione:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic void ConfigureServices(IServiceCollection services)\n{\n\u00a0\u00a0\u00a0\u00a0\/\/ ...\n\u00a0\u00a0\u00a0\u00a0services.AddElasticsearch(Configuration);\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">che ci consente di caricare tutte le impostazioni all\u2019avvio, modificandole nella sezione&nbsp;<strong>elasticsearch&nbsp;<\/strong>del file&nbsp;<em>appsettings.json<\/em>, in cui provvediamo ad inserire le seguenti righe:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n&quot;elasticsearch&quot;: {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&quot;index&quot;: &quot;products&quot;,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&quot;url&quot;: &quot;http:\/\/localhost:9200\/&quot;\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Il parametro&nbsp;<strong>index<\/strong>&nbsp;rappresenta l\u2019indice di default scelto per salvare i nostri documenti e&nbsp;<strong>url<\/strong>&nbsp;\u00e8 l\u2019indirizzo della nostra istanza di ElasticSearch.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Il nostro oggetto Product, \u00e8 cos\u00ec definito:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic class Product\n{\npublic int Id { get; set; }\npublic string Ean { get; set; }\npublic string Name { get; set; }\npublic string Description { get; set; }\npublic string Brand { get; set; }\npublic string Category { get; set; }\npublic string Price { get; set; }\npublic int Quantity { get; set; }\npublic float Rating { get; set; }\npublic DateTime ReleaseDate { get; set; }\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">I prodotti possono essere indicizzati, come detto prima, sia singolarmente che in liste.<br>Nel nostro service dei prodotti abbiamo implementato entrambe le modalit\u00e0:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic async Task SaveSingleAsync(Product product)\n{\n\u00a0\u00a0\u00a0\u00a0if (_cache.Any(p =&gt; p.Id == product.Id))\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0await _elasticClient.UpdateAsync&lt;Product&gt;(product, u =&gt; u.Doc(product));\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0else\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0_cache.Add(product);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0await _elasticClient.IndexDocumentAsync(product);\n\u00a0\u00a0\u00a0\u00a0}\n}\n\u00a0\npublic async Task SaveManyAsync(Product&#x5B;] products)\n{\n\u00a0\u00a0\u00a0\u00a0_cache.AddRange(products);\n\u00a0\u00a0\u00a0\u00a0var result = await _elasticClient.IndexManyAsync(products);\n\u00a0\u00a0\u00a0\u00a0if (result.Errors)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ the response can be inspected for errors\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0foreach (var itemWithError in result.ItemsWithErrors)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0_logger.LogError(&quot;Failed to index document {0}: {1}&quot;,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0itemWithError.Id, itemWithError.Error);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0}\n}\n\u00a0\npublic async Task SaveBulkAsync(Product&#x5B;] products)\n{\n\u00a0\u00a0\u00a0\u00a0_cache.AddRange(products);\n\u00a0\u00a0\u00a0\u00a0var result = await _elasticClient.BulkAsync(b =&gt; b.Index(&quot;products&quot;).IndexMany(products));\n\u00a0\u00a0\u00a0\u00a0if (result.Errors)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ the response can be inspected for errors\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0foreach (var itemWithError in result.ItemsWithErrors)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0_logger.LogError(&quot;Failed to index document {0}: {1}&quot;,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0itemWithError.Id, itemWithError.Error);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0}\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">dove abbiamo utilizzato un array _cache per avere un\u2019ulteriore cache dei prodotti.<br>Per la modalit\u00e0 multipla, abbiamo implementato anche la versione bulk, che ci consente di indicizzare una grossa mole di documenti in tempi molto pi\u00f9 brevi, ed abbiamo gestito gli eventuali errori in inserimento con dei log.<br>Da notare che il metodo SaveSingleAsync gestisce sia l\u2019inserimento che la modifica del documento tramite un controllo sul nostro array di cache.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Per la cancellazione del documento, abbiamo implementato un metodo DeleteAsync:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic async Task DeleteAsync(Product product)\n{\n\u00a0\u00a0\u00a0\u00a0await _elasticClient.DeleteAsync&lt;Product&gt;\n(product);\n\u00a0\n\u00a0\u00a0\u00a0\u00a0if (_cache.Contains(product))\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0_cache.Remove(product);\n\u00a0\u00a0\u00a0\u00a0}\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Il documento, una volta cancellato da ElasticSearch viene rimosso anche dalla nostra cache.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Per la ricerca dei documenti, abbiamo implementato SearchController, col suo metodo principale Find, che prende in input una stringa, numero e dimensione di pagina, e restituisce una view con i documenti trovati.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n&#x5B;Route(&quot;\/search&quot;)]\npublic async Task&lt;IActionResult&gt;Find(string query, int page = 1, int pageSize = 5)\n{\n\u00a0\u00a0\u00a0\u00a0var response = await _elasticClient.SearchAsync&lt;Product&gt;\n(\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s =&gt;s.Query(q =&gt; q.QueryString(d =&gt; d.Query(query)))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.From((page - 1) * pageSize)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Size(pageSize));\n\u00a0\n\u00a0\u00a0\u00a0\u00a0if (!response.IsValid)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ We could handle errors here by checking response.OriginalException \n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/or response.ServerError properties\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0_logger.LogError(&quot;Failed to search documents&quot;);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return View(&quot;Results&quot;, new Product&#x5B;] { });\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0\u00a0\u00a0if (page &gt; 1)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ViewData&#x5B;&quot;prev&quot;] = GetSearchUrl(query, page - 1, pageSize);\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0\u00a0\u00a0if (response.IsValid &amp;&amp; response.Total &gt; page * pageSize)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ViewData&#x5B;&quot;next&quot;] = GetSearchUrl(query, page + 1, pageSize);\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0\u00a0\u00a0return View(&quot;Results&quot;, response.Documents);\n}\n\u00a0\nprivate static string GetSearchUrl(string query, int page, int pageSize)\n{\n\u00a0\u00a0\u00a0\u00a0return $&quot;\/search?query={Uri.EscapeDataString(query ?? &quot;&quot;)}&amp;page={page}&amp;pagesize={pageSize}\/&quot;;\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Il metodo GetSearchUrl ci consente di ottenere la URL per gestire la paginazione.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ai fini di sviluppo, abbiamo implementato il metodo ReInlex, che ci consente di cancellare tutti i documenti sull\u2019indice e importarli di nuovo ad uno ad uno. Pu\u00f2 esserci utile per importare liste di documenti gi\u00e0 esistenti e non caricati.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\/\/Only for development purpose\n&#x5B;HttpGet(&quot;\/search\/reindex&quot;)]\npublic async Task&lt;IActionResult&gt;ReIndex()\n{\n\u00a0\u00a0\u00a0\u00a0await _elasticClient.DeleteByQueryAsync&lt;Product&gt;(q =&gt; q.MatchAll());\n\u00a0\n\u00a0\u00a0\u00a0\u00a0var allProducts = (await _productService.GetProducts(int.MaxValue)).ToArray();\n\u00a0\n\u00a0\u00a0\u00a0\u00a0foreach (var product in allProducts)\n\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0await _elasticClient.IndexDocumentAsync(product);\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0\u00a0\u00a0return Ok($&quot;{allProducts.Length} product(s) reindexed&quot;);\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Ai fini di esempio, abbiamo realizzato un\u2019interfaccia tramite la quale possiamo aggiungere N prodotti generati dinamicamente, tramite il plugin&nbsp;<strong>Bogus<\/strong>, e gestire il CRUD dei prodotti.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lanciando il progetto, otteniamo la seguente schermata:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1018\" height=\"514\" data-attachment-id=\"27519\" data-permalink=\"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/attachment\/image07-8\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image07-8.png?fit=1018%2C514&amp;ssl=1\" data-orig-size=\"1018,514\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"image07-8\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image07-8.png?fit=1018%2C514&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image07-8.png?resize=1018%2C514&#038;ssl=1\" alt=\"\" class=\"wp-image-27519\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image07-8.png 1018w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image07-8-980x495.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image07-8-480x242.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1018px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Se proviamo ad aggiungere, ad esempio, 10 prodotti al nostro indice, inserendo&nbsp;<strong>10&nbsp;<\/strong>nella casella di testo e cliccando su&nbsp;<strong>Import Documents<\/strong>, possiamo visualizzare il risultato della nostra importazione sia utilizzando la casella di ricerca, ma anche direttamente da browser, all\u2019indirizzo <a href=\"http:\/\/localhost:9200\/products\/_search\" rel=\"nofollow\">http:\/\/localhost:9200\/products\/_search<\/a>, dove otterremo un risultato simile a questo:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"847\" height=\"585\" data-attachment-id=\"27522\" data-permalink=\"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/attachment\/image06-8\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image06-8.png?fit=847%2C585&amp;ssl=1\" data-orig-size=\"847,585\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"image06-8\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image06-8.png?fit=847%2C585&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image06-8.png?resize=847%2C585&#038;ssl=1\" alt=\"\" class=\"wp-image-27522\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image06-8.png 847w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/image06-8-480x332.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 847px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Il codice utilizzato in questo articolo \u00e8 disponibile&nbsp;<a href=\"https:\/\/github.com\/enricobencivenga\/ElasticSearch\" target=\"_blank\" rel=\"noreferrer noopener\">qui<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Alla prossima!<\/p>\n\n\n\n\n","protected":false},"excerpt":{"rendered":"<p>Vediamo come aggiungere ricerche full-text alle nostre applicazioni ASP.NET Core con ElasticSearch<\/p>\n","protected":false},"author":196716247,"featured_media":27499,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"off","_et_pb_old_content":"","_et_gb_content_width":"","_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","inline_featured_image":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_wpcom_ai_launchpad_first_post":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"{title}\n\n{excerpt}\n\n{url}","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_wpas_customize_per_network":false,"jetpack_post_was_ever_published":false},"categories":[688637374],"tags":[688637414,688637382,688637418],"class_list":["post-27497","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","tag-asp-net-core","tag-c","tag-elasticsearch"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Integrare ElasticSearch in ASP.NET Core - Blexin<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/\" \/>\n<meta property=\"og:locale\" content=\"it_IT\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Integrare ElasticSearch in ASP.NET Core - Blexin\" \/>\n<meta property=\"og:description\" content=\"Vediamo come aggiungere ricerche full-text alle nostre applicazioni ASP.NET Core con ElasticSearch\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/\" \/>\n<meta property=\"og:site_name\" content=\"Blexin\" \/>\n<meta property=\"article:published_time\" content=\"2020-01-21T23:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-01-13T08:40:16+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/i2.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image00-12.png?fit=1024%2C608&ssl=1\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"608\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Enrico Bencivenga\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Scritto da\" \/>\n\t<meta name=\"twitter:data1\" content=\"Enrico Bencivenga\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tempo di lettura stimato\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minuti\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/integrare-elasticsearch-in-asp-net-core\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/integrare-elasticsearch-in-asp-net-core\\\/\"},\"author\":{\"name\":\"Enrico Bencivenga\",\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/#\\\/schema\\\/person\\\/74e4443d1d7ad12d5b4a8db7f63f0194\"},\"headline\":\"Integrare ElasticSearch in ASP.NET Core\",\"datePublished\":\"2020-01-21T23:00:00+00:00\",\"dateModified\":\"2021-01-13T08:40:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/integrare-elasticsearch-in-asp-net-core\\\/\"},\"wordCount\":1971,\"image\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/integrare-elasticsearch-in-asp-net-core\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2020\\\/12\\\/image00-12.png?fit=1024%2C608&ssl=1\",\"keywords\":[\"Asp.net core\",\"C#\",\"Elasticsearch\"],\"articleSection\":[\"Blog\"],\"inLanguage\":\"it-IT\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/integrare-elasticsearch-in-asp-net-core\\\/\",\"url\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/integrare-elasticsearch-in-asp-net-core\\\/\",\"name\":\"Integrare ElasticSearch in ASP.NET Core - Blexin\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/integrare-elasticsearch-in-asp-net-core\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/integrare-elasticsearch-in-asp-net-core\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2020\\\/12\\\/image00-12.png?fit=1024%2C608&ssl=1\",\"datePublished\":\"2020-01-21T23:00:00+00:00\",\"dateModified\":\"2021-01-13T08:40:16+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/#\\\/schema\\\/person\\\/74e4443d1d7ad12d5b4a8db7f63f0194\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/integrare-elasticsearch-in-asp-net-core\\\/#breadcrumb\"},\"inLanguage\":\"it-IT\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/integrare-elasticsearch-in-asp-net-core\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/integrare-elasticsearch-in-asp-net-core\\\/#primaryimage\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2020\\\/12\\\/image00-12.png?fit=1024%2C608&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2020\\\/12\\\/image00-12.png?fit=1024%2C608&ssl=1\",\"width\":1024,\"height\":608},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/integrare-elasticsearch-in-asp-net-core\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/blexin.com\\\/it\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Integrare ElasticSearch in ASP.NET Core\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/#website\",\"url\":\"https:\\\/\\\/blexin.com\\\/it\\\/\",\"name\":\"Blexin\",\"description\":\"Con noi \u00e8 semplice\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/blexin.com\\\/it\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"it-IT\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/#\\\/schema\\\/person\\\/74e4443d1d7ad12d5b4a8db7f63f0194\",\"name\":\"Enrico Bencivenga\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4ea7187309674789d6f02c6b757e1f21c8cf800abb2419b4edaa8b09d4c99548?s=96&d=identicon&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4ea7187309674789d6f02c6b757e1f21c8cf800abb2419b4edaa8b09d4c99548?s=96&d=identicon&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4ea7187309674789d6f02c6b757e1f21c8cf800abb2419b4edaa8b09d4c99548?s=96&d=identicon&r=g\",\"caption\":\"Enrico Bencivenga\"},\"url\":\"https:\\\/\\\/blexin.com\\\/it\\\/author\\\/enrico-bencivengablexin-com\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Integrare ElasticSearch in ASP.NET Core - Blexin","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/","og_locale":"it_IT","og_type":"article","og_title":"Integrare ElasticSearch in ASP.NET Core - Blexin","og_description":"Vediamo come aggiungere ricerche full-text alle nostre applicazioni ASP.NET Core con ElasticSearch","og_url":"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/","og_site_name":"Blexin","article_published_time":"2020-01-21T23:00:00+00:00","article_modified_time":"2021-01-13T08:40:16+00:00","og_image":[{"width":1024,"height":608,"url":"https:\/\/i2.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image00-12.png?fit=1024%2C608&ssl=1","type":"image\/png"}],"author":"Enrico Bencivenga","twitter_card":"summary_large_image","twitter_misc":{"Scritto da":"Enrico Bencivenga","Tempo di lettura stimato":"12 minuti"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/#article","isPartOf":{"@id":"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/"},"author":{"name":"Enrico Bencivenga","@id":"https:\/\/blexin.com\/it\/#\/schema\/person\/74e4443d1d7ad12d5b4a8db7f63f0194"},"headline":"Integrare ElasticSearch in ASP.NET Core","datePublished":"2020-01-21T23:00:00+00:00","dateModified":"2021-01-13T08:40:16+00:00","mainEntityOfPage":{"@id":"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/"},"wordCount":1971,"image":{"@id":"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image00-12.png?fit=1024%2C608&ssl=1","keywords":["Asp.net core","C#","Elasticsearch"],"articleSection":["Blog"],"inLanguage":"it-IT"},{"@type":"WebPage","@id":"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/","url":"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/","name":"Integrare ElasticSearch in ASP.NET Core - Blexin","isPartOf":{"@id":"https:\/\/blexin.com\/it\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/#primaryimage"},"image":{"@id":"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image00-12.png?fit=1024%2C608&ssl=1","datePublished":"2020-01-21T23:00:00+00:00","dateModified":"2021-01-13T08:40:16+00:00","author":{"@id":"https:\/\/blexin.com\/it\/#\/schema\/person\/74e4443d1d7ad12d5b4a8db7f63f0194"},"breadcrumb":{"@id":"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/#breadcrumb"},"inLanguage":"it-IT","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/"]}]},{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/#primaryimage","url":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image00-12.png?fit=1024%2C608&ssl=1","contentUrl":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image00-12.png?fit=1024%2C608&ssl=1","width":1024,"height":608},{"@type":"BreadcrumbList","@id":"https:\/\/blexin.com\/it\/blog\/integrare-elasticsearch-in-asp-net-core\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blexin.com\/it\/"},{"@type":"ListItem","position":2,"name":"Integrare ElasticSearch in ASP.NET Core"}]},{"@type":"WebSite","@id":"https:\/\/blexin.com\/it\/#website","url":"https:\/\/blexin.com\/it\/","name":"Blexin","description":"Con noi \u00e8 semplice","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blexin.com\/it\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"it-IT"},{"@type":"Person","@id":"https:\/\/blexin.com\/it\/#\/schema\/person\/74e4443d1d7ad12d5b4a8db7f63f0194","name":"Enrico Bencivenga","image":{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/secure.gravatar.com\/avatar\/4ea7187309674789d6f02c6b757e1f21c8cf800abb2419b4edaa8b09d4c99548?s=96&d=identicon&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/4ea7187309674789d6f02c6b757e1f21c8cf800abb2419b4edaa8b09d4c99548?s=96&d=identicon&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/4ea7187309674789d6f02c6b757e1f21c8cf800abb2419b4edaa8b09d4c99548?s=96&d=identicon&r=g","caption":"Enrico Bencivenga"},"url":"https:\/\/blexin.com\/it\/author\/enrico-bencivengablexin-com\/"}]}},"jetpack_publicize_connections":[],"jetpack_shortlink":"https:\/\/wp.me\/pcyUBx-79v","jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/image00-12.png?fit=1024%2C608&ssl=1","_links":{"self":[{"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/posts\/27497","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/users\/196716247"}],"replies":[{"embeddable":true,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/comments?post=27497"}],"version-history":[{"count":11,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/posts\/27497\/revisions"}],"predecessor-version":[{"id":27826,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/posts\/27497\/revisions\/27826"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/media\/27499"}],"wp:attachment":[{"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/media?parent=27497"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/categories?post=27497"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/tags?post=27497"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}