{"id":27095,"date":"2020-04-01T00:00:00","date_gmt":"2020-03-31T22:00:00","guid":{"rendered":"https:\/\/blexin.com\/?p=27095"},"modified":"2021-05-21T19:55:17","modified_gmt":"2021-05-21T17:55:17","slug":"elasticsearch-funzionalita-avanzate","status":"publish","type":"post","link":"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/","title":{"rendered":"ElasticSearch: funzionalit\u00e0 avanzate"},"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=\"27097\" data-permalink=\"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/attachment\/top00-2\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/top00-2.png?fit=1024%2C608&amp;ssl=1\" data-orig-size=\"1024,608\" data-comments-opened=\"0\" data-image-title=\"top00-2\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/top00-2.png?fit=1024%2C608&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/top00-2.png?resize=1024%2C608&#038;ssl=1\" alt=\"\" class=\"wp-image-27097\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/top00-2.png 1024w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/top00-2-980x582.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/top00-2-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\">Nel mio precedente&nbsp;<a href=\"https:\/\/www.blexin.com\/it-IT\/Article\/Blog\/Integrare-ElasticSearch-in-ASPNET-Core-70\" target=\"_blank\" rel=\"noreferrer noopener\">articolo<\/a>, abbiamo discusso dell\u2019utilizzo di ElasticSearch come semplice motore di ricerca full-text, di come installarlo e configurarlo in maniera veloce per integrarlo nella nostra applicazione .NET tramite il plugin NEST.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Oggi mostreremo, sempre nell\u2019ambito di un sito e-commerce, come abbiamo utilizzato le funzionalit\u00e0 offerte dal motore per migliorare l\u2019accuratezza delle nostre ricerche.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Avevamo utilizzato una classe flat Product senza classi innestate per gestire la ricerca con semplicit\u00e0 ma, naturalmente, \u00e8 un approccio che ha delle limitazioni. Abbiamo, quindi, introdotto un nuovo modello dei dati, in cui ogni nuovo oggetto \u00e8 un\u2019entit\u00e0 da modellare.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Un documento pu\u00f2 contenere un numero indefinito di campi e valori (array, tipi semplici e complessi) associati a esso e, ricordiamo, \u00e8 indicizzato in formato JSON.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La nostra classe di modello Product \u00e8 quindi diventata:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic class Product\n{\n    public int Id { get; set; }\n    public string Ean { get; set; }\n    public string Name { get; set; }\n    public string Description { get; set; }\n    public Brand Brand { get; set; }\n    public Category Category { get; set; }\n    public Store Store { get; set; }\n    public decimal Price { get; set; }\n    public string Currency { get; set; }\n    public int Quantity { get; set; }\n    public float Rating { get; set; }\n    public DateTime ReleaseDate { get; set; }\n    public string Image { get; set; }\n    public List&lt;Review&gt; Reviews { get; set; }\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">dove le classi Brand, Category, Store, Review e User sono rispettivamente:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic class Brand\n{\n    public int Id { get; set; }\n    public string Name { get; set; }\n    public string Description { get; set; }\n}\n \npublic class Category\n{\n    public int Id { get; set; }\n    public string Name { get; set; }\n    public string Description { get; set; }\n}\n \npublic class Store\n{\n    public int Id { get; set; }\n    public string Name { get; set; }\n    public string Description { get; set; }\n}\n \npublic class Review\n{\n    public int Id { get; set; }\n    public short Rating { get; set; }\n    public string Description { get; set; }\n    public User User { get; set; }\n}\n \npublic class User\n{\n    public int Id { get; set; }\n    public string FirstName { get; set; }\n    public string LastName { get; set; }\n    public string IPAddress { get; set; }\n    public GeoIp GeoIp { get; set; }\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">in cui GeoIp \u00e8 una classe della libreria NEST utilizzata per i riferimenti geografici.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">L\u2019indice per i prodotti \u00e8 stato chiamato&nbsp;<em>products<\/em>. L\u2019abbiamo creato e configurato cos\u00ec:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nclient.Indices.Create(\u201cproducts\u201d, index =&gt; index\n    .Map&lt;Product&gt;(x =&gt; x.AutoMap())\n    .Map&lt;Brand&gt;(x =&gt; x.AutoMap())\n    .Map&lt;Category&gt;(x =&gt; x.AutoMap())\n    .Map&lt;Store&gt;(x =&gt; x.AutoMap())\n    .Map&lt;Review&gt;(x =&gt; x.AutoMap())\n    .Map&lt;User&gt;(x =&gt;\n        x.AutoMap()\n        .Properties(props =&gt; props\n            .Keyword(t =&gt; t.Name(&quot;fullname&quot;))\n            .Ip(t =&gt; t.Name(dv =&gt; dv.IPAddress))\n            .Object&lt;GeoIp&gt;(t =&gt; t.Name(dv =&gt; dv.GeoIp))\n        )\n    )\n)\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Abbiamo creato, appositamente per l\u2019indice di ElasticSearch, una nuova propriet\u00e0&nbsp;<em>fullname&nbsp;<\/em>per la classe User, e definito quali sono le informazioni geografiche che verranno poi elaborate.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Per far fronte alla necessit\u00e0 di elaborare i nostri prodotti prima dell\u2019indicizzazione, uno strumento utilissimo \u00e8 l\u2019<em>ingest node<\/em>, che \u00e8 un nodo su cui avviene il pre-processing dei documenti. L\u2019ingest node intercetta tutte le richieste di indicizzazione, comprese le bulk, applica le trasformazioni sul contenuto, e restituisce il documento all\u2019API di indicizzazione.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">L\u2019ingest va abilitato nel file di configurazione&nbsp;<em>elasticsearch.yml<\/em>, tramite il parametro:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>node.ingest: true<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Nel nostro caso, in cui il nodo \u00e8 unico sia per la ricerca che per l\u2019ingest, non abbiamo bisogno di impostazioni specifiche nel codice, ma nel caso di ingest nodes dedicati, il client di ElasticSearch andrebbe configurato cos\u00ec:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nvar pool = new StaticConnectionPool(new &#x5B;] \n{\n\u00a0\u00a0\u00a0\u00a0new Uri(&quot;http:\/\/ingestnode1:9200&quot;),\n\u00a0\u00a0\u00a0\u00a0new Uri(&quot;http:\/\/ingestnode2:9200&quot;),\n\u00a0\u00a0\u00a0\u00a0new Uri(&quot;http:\/\/ingestnode3:9200&quot;)\n});\nvar settings = new ConnectionSettings(pool);\nvar client = new ElasticClient(settings);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Per pre-processare il documento prima dell\u2019indicizzazione \u00e8 necessario definire una pipeline che specifichi una serie di processi che trasformano il documento. Esistono diversi processi predefiniti, gi\u00e0 pronti da utilizzare, tra cui GeoIP (per ottenere indicazioni geografiche a partire da un IP), JSON (converte una stringa in un oggetto JSON), Lowercase e Uppercase, Drop (elimina i documenti con caratteristiche specificate) ed \u00e8 inoltre possibile creare processi custom.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La pipeline che abbiamo utilizzato nel nostro caso di esempio \u00e8 la seguente:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nclient.Ingest.PutPipeline(&quot;product-pipeline&quot;, p =&gt; p\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Processors(ps =&gt; ps\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Uppercase&lt;Brand&gt;(s =&gt; s\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Field(t =&gt; t.Name)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Uppercase&lt;Category&gt;(s =&gt; s\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Field(t =&gt; t.Name)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Set&lt;User&gt;(s =&gt; s.Field(&quot;fullname&quot;)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Value(s.Field(f =&gt; f.FirstName) + &quot; &quot; + \n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.Field(f =&gt; f.LastName)))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.GeoIp&lt;User&gt;(s =&gt; s\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Field(i =&gt; i.IPAddress)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.TargetField(i =&gt; i.GeoIp)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Questa pipeline elabora i documenti in modo che:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>i campi name di Brand e Category vengano indicizzati in maiuscolo tramite l\u2019ingest Uppercase;<\/li><li>il campo fullname di User contenga firstName e lastName tramite l\u2019ingest Set;<\/li><li>il campo IPAddress di User diventi un indirizzo geolocalizzato tramite l\u2019ingest GeoIp.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Le pipeline vengono salvate nello stato del cluster di ElasticSearch, e, per utilizzarle, basta specificare il parametro della pipeline nella richiesta di indicizzazione cosicch\u00e9 l\u2019ingest node sappia quale pipeline utilizzare:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nclient.Bulk(b =&gt; b\n\u00a0\u00a0\u00a0\u00a0.Index(&quot;products&quot;)\n\u00a0\u00a0\u00a0\u00a0.Pipeline(&quot;product-pipeline&quot;)\n\u00a0\u00a0\u00a0\u00a0.Timeout(&quot;5m&quot;) \n\u00a0\u00a0\u00a0\u00a0.Index&lt;Person&gt;(\/*snip*\/)\n\u00a0\u00a0\u00a0\u00a0.Index&lt;Person&gt;(\/*snip*\/)\n\u00a0\u00a0\u00a0\u00a0.Index&lt;Person&gt;(\/*snip*\/)\n\u00a0\u00a0\u00a0\u00a0.RequestConfiguration(rc =&gt; rc\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.RequestTimeout(TimeSpan.FromMinutes(5)) \n\u00a0\u00a0\u00a0\u00a0)\n);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Con queste operazioni abbiamo definito il processo di indicizzazione al fine di ottenere una lista di documenti indicizzati congrui alle nostre esigenze.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dopo aver indicizzato i documenti con le pipeline definite, possiamo controllare subito la corretta indicizzazione andando col browser alla pagina&nbsp;<a href=\"http:\/\/localhost:9200\/products\/_search\" rel=\"nofollow\">http:\/\/localhost:9200\/products\/_search<\/a>, in cui 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=\"943\" height=\"471\" data-attachment-id=\"27102\" data-permalink=\"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/attachment\/elasticsearch-home\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/elasticsearch-home.png?fit=943%2C471&amp;ssl=1\" data-orig-size=\"943,471\" data-comments-opened=\"0\" data-image-title=\"elasticsearch-home\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/elasticsearch-home.png?fit=943%2C471&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/elasticsearch-home.png?resize=943%2C471&#038;ssl=1\" alt=\"\" class=\"wp-image-27102\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/elasticsearch-home.png 943w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/elasticsearch-home-480x240.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 943px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Il processo di ricerca, come specificato nel precedente articolo, si basa sull\u2019analisi dei documenti, ovvero il processo di tokenizzazione (divisione di un testo in piccole parti, chiamate token) e normalizzazione (consente di trovare corrispondenze ai token che non sono esattamente uguali alle parole cercate, ma simili abbastanza da essere rilevanti) del testo indicizzato per la ricerca, che avviene tramite un analyzer.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Un analyzer \u00e8 composto da tre componenti:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>0 o pi\u00f9 filtri sui caratteri<\/li><li>1 tokenizzatore<\/li><li>0 o pi\u00f9 filtri sui token<\/li><\/ol>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"417\" data-attachment-id=\"27105\" data-permalink=\"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/attachment\/analysis-chain\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/analysis-chain.png?fit=1807%2C735&amp;ssl=1\" data-orig-size=\"1807,735\" data-comments-opened=\"0\" data-image-title=\"analysis-chain\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/analysis-chain.png?fit=1024%2C417&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/analysis-chain.png?resize=1024%2C417&#038;ssl=1\" alt=\"\" class=\"wp-image-27105\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/analysis-chain-980x399.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/analysis-chain-480x195.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\">Esistono degli analyzer predefiniti e pronti da utilizzare, ma, per migliorare l\u2019accuratezza delle ricerche, anche a seconda delle nostre esigenze, abbiamo creato un custom analyzer.<br>Un custom analyzer consente di avere il controllo, delle modifiche al testo prima della tokenizzazione durante l\u2019analisi, di come il testo venga convertito in token e delle modalit\u00e0 di normalizzazione.<br>Il nostro custom analyzer si presenta cos\u00ec:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nvar an = new CustomAnalyzer();\nan.CharFilter = new List&lt;string&gt;();\nan.CharFilter.Add(&quot;html_strip&quot;);\nan.Tokenizer = &quot;edgeNGram&quot;;\nan.Filter = new List&lt;string&gt;();\nan.Filter.Add(&quot;standard&quot;);\nan.Filter.Add(&quot;lowercase&quot;);\nan.Filter.Add(&quot;stop&quot;);\n \nsettings.Analysis.Tokenizers.Add(&quot;edgeNGram&quot;, new Nest.EdgeNGramTokenizer\n{\n    MaxGram = 15,\n    MinGram = 3\n});\n \nsettings.Analysis.Analyzers.Add(&quot;product-analyzer&quot;, an);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Il nostro analyzer crea token in lowercase, utilizzando la tokenizzazione standard, da 3 a 15 caratteri. Possiamo aggiungere il nostro analyzer all\u2019indice creato per il prodotti, o in corrispondenza di uno o pi\u00f9 campi o come analyzer standard.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nclient.CreateIndex(&quot;products&quot;, c =&gt; c\n\u00a0\u00a0\u00a0\u00a0\/\/ Analyzer aggiunto solo per la propriet\u00e0 Description di Product\n\u00a0\u00a0\u00a0\u00a0.AddMapping&lt;Product&gt;(e =&gt; e\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.MapFromAttributes()\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Properties(p =&gt; p.String(s =&gt; s.Name(f =&gt; f.Description)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Analyzer(&quot;product-analyzer&quot;)))\n\u00a0\u00a0\u00a0\u00a0)\n\u00a0\u00a0\u00a0\u00a0\/\/Analyzer aggiunto come default\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Analysis(analysis =&gt; analysis\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Analyzers(a =&gt; a\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Add(&quot;default&quot;, an)\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\">Quando creiamo un custom analyzer possiamo anche testarlo tramite le testing API. I test naturalmente possono essere effettuati anche sugli analyzer predefiniti.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nvar analyzeResponse = client.Indices.Analyze(a =&gt; a\n\u00a0\u00a0\u00a0\u00a0.Tokenizer(&quot;standard&quot;)\n\u00a0\u00a0\u00a0\u00a0.Filter(&quot;lowercase&quot;, &quot;stop&quot;)\n\u00a0\u00a0\u00a0\u00a0.Text(&quot;Lorem ipsum dolor sit amet, consectetur...&quot;)\n);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Un altro strumento che ci risulta utile \u00e8 l\u2019aggregazione dei dati che ci fornisce dati aggregati a partire dalla query di ricerca, e si basa su blocchi semplici che possono essere via via composti per creare aggregazioni pi\u00f9 complesse di dati.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ci sono differenti tipi di aggregazione, ognuna con uno scopo e un output definiti. Esse si possono suddividere in:&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Bucketing: contenitori a cui sono associati una chiave e un criterio;<\/li><li>Metric: metriche calcolate su un insieme di documenti;<\/li><li>Matrix: una serie di operazioni effettuate su pi\u00f9 campi del documento che producono dati in forma matriciale;<\/li><li>Pipeline: aggregazione di pi\u00f9 aggregazioni.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Nel nostro caso, abbiamo utilizzato le aggregazioni per ottenere il numero di prodotti per brand, categorie, fasce di prezzo. Qui, ad esempio, un aggregato del prezzo dei prodotti per i parametri di ricerca:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\ns =&gt; s\n    .Query(...)\n    .Aggregations(aggs =&gt; aggs\n        .Average(&quot;average_price&quot;, avg =&gt; avg.Field(p =&gt; p.Price))\n        .Max(&quot;max_price&quot;, avg =&gt; avg.Field(p =&gt; p.Price))\n        .Min(&quot;min_price&quot;, avg =&gt; avg.Field(p =&gt; p.Price))\n    )\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Un\u2019altra aggregazione utile \u00e8 il raggruppamento per brand, store o categoria:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\ns =&gt; s\n\u00a0\u00a0\u00a0\u00a0\u00a0.Query(...)\n\u00a0\u00a0\u00a0\u00a0\u00a0.Aggregations(aggs =&gt; aggs\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.ValueCount(&quot;products_for_category&quot;, avg =&gt; avg.Field(p =&gt; p.Category.Name))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.ValueCount(&quot;products_for_brand&quot;, avg =&gt; avg.Field(p =&gt; p.Brand.Name))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.ValueCount(&quot;products_for_store&quot;, avg =&gt; avg.Field(p =&gt; p.Store.Name))\n\u00a0\u00a0\u00a0\u00a0\u00a0)\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">In questo modo, possiamo avere, in tempo reale, quanti prodotti della ricerca effettuata sono presenti per categoria, brand e store. I dati aggregati sono molto utili anche per creare delle dashboard o organizzare delle ricerche con filtri dinamici, oltre che naturalmente ai fini statistici.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Migliorare le ricerche<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Come abbiamo precedentemente visto, a ogni risultato della ricerca \u00e8 associato uno score, ovvero un numero che determina quanto vicino sia il parametro di ricerca fornito a quel particolare risultato. Lo score dipende fondamentalmente da 3 parametri: la frequenza del termine ricercato, frequenza del documento invertito, lunghezza del campo su cui si cerca.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Per escludere dai risultati della ricerca quelli che hanno uno score troppo basso, possiamo utilizzare il MinScore:<a href=\"https:\/\/www.blexin.com\/it-IT\/Article\/Blog\/ElasticSearch-funzionalit-avanzate-80#\">?<\/a><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\ns =&gt; s\n\u00a0\u00a0\u00a0\u00a0\u00a0.MinScore(0.5)\n\u00a0\u00a0\u00a0\u00a0\u00a0.Query(...)\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">In questo modo escludiamo tutti i risultati che hanno uno score inferiore allo 0.5.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I suggesters sono dei metodi che consentono la ricerca su ElasticSearch utilizzando termini simili a quelli del testo di ricerca. Il completion suggester, ad esempio, \u00e8 molto utile per l\u2019autocomplete, che consente di guidare l\u2019utente verso i risultati pi\u00f9 rilevanti mentre sta digitando del testo. Il completion suggester \u00e8 naturalmente ottimizzato per restituire i risultati pi\u00f9 velocemente possibile, per cui utilizza strutture che abilitano il fast lookup ma che, naturalmente, richiedono risorse.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Nel nostro caso, abbiamo realizzato un metodo di autocomplete sul nome del prodotto, che viene invocato ogni volta che si digita nella casella di ricerca:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\ns =&gt; s\n\u00a0\u00a0\u00a0\u00a0.Query(...)\n\u00a0\u00a0\u00a0\u00a0.Suggest(su =&gt; su\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Completion(&quot;name&quot;, cs =&gt; cs\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Field(f =&gt; f.Name)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Fuzzy(f =&gt; f\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Fuzziness(Fuzziness.Auto)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Size(5)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0)\n\u00a0\u00a0\u00a0\u00a0)\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Un altro metodo di ricerca che ci \u00e8 risultato utile \u00e8 l\u2019<em>indices boost<\/em>, ovvero, la possibilit\u00e0 di assegnare dei moltiplicatori agli indici in modo da favorire i risultati di uno degli indici a discapito degli altri, quando si ricerca su pi\u00f9 indici. Pu\u00f2 essere molto utile in caso di particolari accordi commerciali con i fornitori dei prodotti dell\u2019e-commerce o, banalmente, per dare risalto ai prodotti del proprio store.<br>Un esempio di indices boost \u00e8:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\ns =&gt; s\n\u00a0\u00a0\u00a0\u00a0.Query(...)\n\u00a0\u00a0\u00a0\u00a0.IndicesBoost(b =&gt; b\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Add(&quot;products-1&quot;, 1.5)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Add(&quot;products-2&quot;, 1)\n\u00a0\u00a0\u00a0\u00a0)\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Nell\u2019esempio abbiamo assegnato un coefficiente di 1.5 ai risultati dell\u2019indice products-1 e 1 ai risultati dell\u2019indice products-2, per cui i risultati di products-1 saranno favoriti.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Un\u2019altra modalit\u00e0 per migliorare le ricerche \u00e8 sicuramente l\u2019ordinamento secondo parametri prestabiliti, nel nostro caso abbiamo:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\ns =&gt; s\n\u00a0\u00a0\u00a0\u00a0.Query()\n\u00a0\u00a0\u00a0\u00a0.Sort(ss =&gt; ss\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Descending(SortSpecialField.Score)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Descending(p =&gt; p.Price)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Descending(p =&gt; p.ReleaseDate)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.Ascending(SortSpecialField.DocumentIndexOrder)\n\u00a0\u00a0\u00a0\u00a0)\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">In questo caso, abbiamo dato priorit\u00e0 allo score, poi al prezzo, alla data di introduzione in commercio e infine all\u2019ordine sull\u2019indice.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Esecuzione del progetto<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Il nostro progetto d\u2019esempio \u00e8 un\u2019applicazione .NET Core MVC e WebApi che prevede una dashboard con una casella di ricerca e dei dati automaticamente aggiornati a seconda della stringa inserita. Alla prima esecuzione, possiamo caricare una lista di n oggetti Product, creati randomicamente dal plugin Bogus. A monte ci sono altre classi faker per la costruzione di oggetti random di tipo Brand, Category, Store, Review e User. Questo ci consente di avere una base di dati su cui effettuare le nostre ricerche.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nvar productFaker = new Faker&lt;Product&gt;()\n\u00a0\u00a0\u00a0\u00a0.CustomInstantiator(f =&gt; new Product())\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.RuleFor(p =&gt; p.Id, f =&gt; f.IndexFaker)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.RuleFor(p =&gt; p.Ean, f =&gt; f.Commerce.Ean13())\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.RuleFor(p =&gt; p.Name, f =&gt; f.Commerce.ProductName())\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.RuleFor(p =&gt; p.Description, f =&gt; f.Lorem.Sentence(f.Random.Int(5, 20)))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.RuleFor(p =&gt; p.Brand, f =&gt; f.PickRandom(brands))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.RuleFor(p =&gt; p.Category, f =&gt; f.PickRandom(categories))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.RuleFor(p =&gt; p.Store, f =&gt; f.PickRandom(stores))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.RuleFor(p =&gt; p.Price, f =&gt; f.Finance.Amount(1, 1000, 2))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.RuleFor(p =&gt; p.Currency, &quot;\u20ac&quot;)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.RuleFor(p =&gt; p.Quantity, f =&gt; f.Random.Int(0, 1000))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.RuleFor(p =&gt; p.Rating, f =&gt; f.Random.Float(0, 1))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.RuleFor(p =&gt; p.ReleaseDate, f =&gt; f.Date.Past(2))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.RuleFor(p =&gt; p.Image, f =&gt; f.Image.PicsumUrl())\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.RuleFor(p =&gt; p.Reviews, f =&gt; reviewFaker.Generate(f.Random.Int(0, 1000))\n\u00a0\u00a0\u00a0\u00a0)\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"416\" data-attachment-id=\"27110\" data-permalink=\"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/attachment\/project-home\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/project-home.png?fit=1182%2C480&amp;ssl=1\" data-orig-size=\"1182,480\" data-comments-opened=\"0\" data-image-title=\"project-home\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/project-home.png?fit=1024%2C416&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/project-home.png?resize=1024%2C416&#038;ssl=1\" alt=\"\" class=\"wp-image-27110\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/project-home-1024x416.png 1024w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/project-home-980x398.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/project-home-480x195.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\">Al centro della pagina, \u00e8 presente la dashboard in cui vengono utilizzati i filtri, gli analyzer e i metodi descritti in questo articolo. Digitando del testo nella casella di ricerca in alto, ci vengono suggeriti i prodotti che corrispondono al testo cercato e, contestualmente, viene aggiornato il contenuto della dashboard.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Conclusioni<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In questo articolo, abbiamo visto come utilizzare Elasticsearch per elaborare, analizzare e cercare dati in maniera pi\u00f9 efficace per scenari reali complessi. Mi auguro di aver suscitato il vostro interesse per l\u2019argomento.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Il progetto di esempio col codice utilizzato \u00e8 disponibile&nbsp;<a href=\"https:\/\/github.com\/enricobencivenga\/ProductElasticSearchAdvanced\" target=\"_blank\" rel=\"noreferrer noopener\">qui<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Al prossimo articolo!<\/p>\n\n\n\n\n","protected":false},"excerpt":{"rendered":"<p>Vediamo come sfruttare le funzionalit\u00e0 avanzate di ElasticSearch per la nostra applicazione<\/p>\n","protected":false},"author":196716247,"featured_media":27097,"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":[688637541,688637414,688637382,688637418],"class_list":["post-27095","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","tag-dotnetcore","tag-asp-net-core","tag-c","tag-elasticsearch"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>ElasticSearch: funzionalit\u00e0 avanzate - 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\/elasticsearch-funzionalita-avanzate\/\" \/>\n<meta property=\"og:locale\" content=\"it_IT\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"ElasticSearch: funzionalit\u00e0 avanzate - Blexin\" \/>\n<meta property=\"og:description\" content=\"Vediamo come sfruttare le funzionalit\u00e0 avanzate di ElasticSearch per la nostra applicazione\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/\" \/>\n<meta property=\"og:site_name\" content=\"Blexin\" \/>\n<meta property=\"article:published_time\" content=\"2020-03-31T22:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-05-21T17:55:17+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/i2.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/top00-2.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=\"11 minuti\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/elasticsearch-funzionalita-avanzate\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/elasticsearch-funzionalita-avanzate\\\/\"},\"author\":{\"name\":\"Enrico Bencivenga\",\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/#\\\/schema\\\/person\\\/74e4443d1d7ad12d5b4a8db7f63f0194\"},\"headline\":\"ElasticSearch: funzionalit\u00e0 avanzate\",\"datePublished\":\"2020-03-31T22:00:00+00:00\",\"dateModified\":\"2021-05-21T17:55:17+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/elasticsearch-funzionalita-avanzate\\\/\"},\"wordCount\":1418,\"image\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/elasticsearch-funzionalita-avanzate\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2020\\\/12\\\/top00-2.png?fit=1024%2C608&ssl=1\",\"keywords\":[\".NetCore\",\"Asp.net core\",\"C#\",\"Elasticsearch\"],\"articleSection\":[\"Blog\"],\"inLanguage\":\"it-IT\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/elasticsearch-funzionalita-avanzate\\\/\",\"url\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/elasticsearch-funzionalita-avanzate\\\/\",\"name\":\"ElasticSearch: funzionalit\u00e0 avanzate - Blexin\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/elasticsearch-funzionalita-avanzate\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/elasticsearch-funzionalita-avanzate\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2020\\\/12\\\/top00-2.png?fit=1024%2C608&ssl=1\",\"datePublished\":\"2020-03-31T22:00:00+00:00\",\"dateModified\":\"2021-05-21T17:55:17+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/#\\\/schema\\\/person\\\/74e4443d1d7ad12d5b4a8db7f63f0194\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/elasticsearch-funzionalita-avanzate\\\/#breadcrumb\"},\"inLanguage\":\"it-IT\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/elasticsearch-funzionalita-avanzate\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/elasticsearch-funzionalita-avanzate\\\/#primaryimage\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2020\\\/12\\\/top00-2.png?fit=1024%2C608&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2020\\\/12\\\/top00-2.png?fit=1024%2C608&ssl=1\",\"width\":1024,\"height\":608},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/blexin.com\\\/it\\\/blog\\\/elasticsearch-funzionalita-avanzate\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/blexin.com\\\/it\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"ElasticSearch: funzionalit\u00e0 avanzate\"}]},{\"@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":"ElasticSearch: funzionalit\u00e0 avanzate - 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\/elasticsearch-funzionalita-avanzate\/","og_locale":"it_IT","og_type":"article","og_title":"ElasticSearch: funzionalit\u00e0 avanzate - Blexin","og_description":"Vediamo come sfruttare le funzionalit\u00e0 avanzate di ElasticSearch per la nostra applicazione","og_url":"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/","og_site_name":"Blexin","article_published_time":"2020-03-31T22:00:00+00:00","article_modified_time":"2021-05-21T17:55:17+00:00","og_image":[{"width":1024,"height":608,"url":"https:\/\/i2.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/top00-2.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":"11 minuti"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/#article","isPartOf":{"@id":"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/"},"author":{"name":"Enrico Bencivenga","@id":"https:\/\/blexin.com\/it\/#\/schema\/person\/74e4443d1d7ad12d5b4a8db7f63f0194"},"headline":"ElasticSearch: funzionalit\u00e0 avanzate","datePublished":"2020-03-31T22:00:00+00:00","dateModified":"2021-05-21T17:55:17+00:00","mainEntityOfPage":{"@id":"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/"},"wordCount":1418,"image":{"@id":"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/top00-2.png?fit=1024%2C608&ssl=1","keywords":[".NetCore","Asp.net core","C#","Elasticsearch"],"articleSection":["Blog"],"inLanguage":"it-IT"},{"@type":"WebPage","@id":"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/","url":"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/","name":"ElasticSearch: funzionalit\u00e0 avanzate - Blexin","isPartOf":{"@id":"https:\/\/blexin.com\/it\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/#primaryimage"},"image":{"@id":"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/top00-2.png?fit=1024%2C608&ssl=1","datePublished":"2020-03-31T22:00:00+00:00","dateModified":"2021-05-21T17:55:17+00:00","author":{"@id":"https:\/\/blexin.com\/it\/#\/schema\/person\/74e4443d1d7ad12d5b4a8db7f63f0194"},"breadcrumb":{"@id":"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/#breadcrumb"},"inLanguage":"it-IT","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/"]}]},{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/#primaryimage","url":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/top00-2.png?fit=1024%2C608&ssl=1","contentUrl":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/top00-2.png?fit=1024%2C608&ssl=1","width":1024,"height":608},{"@type":"BreadcrumbList","@id":"https:\/\/blexin.com\/it\/blog\/elasticsearch-funzionalita-avanzate\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blexin.com\/it\/"},{"@type":"ListItem","position":2,"name":"ElasticSearch: funzionalit\u00e0 avanzate"}]},{"@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-731","jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/top00-2.png?fit=1024%2C608&ssl=1","_links":{"self":[{"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/posts\/27095","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=27095"}],"version-history":[{"count":12,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/posts\/27095\/revisions"}],"predecessor-version":[{"id":27798,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/posts\/27095\/revisions\/27798"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/media\/27097"}],"wp:attachment":[{"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/media?parent=27095"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/categories?post=27095"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/tags?post=27095"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}