{"id":3448,"date":"2021-07-13T07:51:03","date_gmt":"2021-07-13T07:51:03","guid":{"rendered":"https:\/\/cloudsurfers.it\/?p=3448"},"modified":"2021-07-13T09:08:47","modified_gmt":"2021-07-13T09:08:47","slug":"storicizzazione-del-dato-compressione-e-interrogazione-di-strutture-dati-json-in-sql-server","status":"publish","type":"post","link":"https:\/\/cloudsurfers.it\/index.php\/storicizzazione-del-dato-compressione-e-interrogazione-di-strutture-dati-json-in-sql-server\/","title":{"rendered":"Storicizzazione del dato, compressione e interrogazione di strutture dati JSON in SQL Server"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"679\" src=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/07\/database-1024x679.jpg\" alt=\"\" class=\"wp-image-3459\" srcset=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/07\/database-1024x679.jpg 1024w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/07\/database-300x199.jpg 300w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/07\/database-768x509.jpg 768w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/07\/database-600x398.jpg 600w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2021\/07\/database.jpg 1200w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Durante lo sviluppo di software basati su strutture dati relazionali complesse, spesso si ha la necessit\u00e0 di effettuare una storicizzazione del dato, che sia per utilizzi futuri, oppure ai fini di analisi o statistica.<\/p>\n\n\n\n<p>Pi\u00f9 la mole di dati \u00e8 consistente, pi\u00f9 ci si scontra con la necessit\u00e0 di trovare un equilibrio tra prestazione di interrogazione del dato e dimensione che questo occupa sul disco.<\/p>\n\n\n\n<p>In questo articolo vediamo una tecnica di storicizzazione di informazioni in formato <em>JSON<\/em>, effettuando una compressione del dato ed analizzando successivamente le tecniche per interrogarlo.<\/p>\n\n\n\n<p>Per fare ci\u00f2, utilizzeremo diversi strumenti introdotti con la versione <strong>SQL Server 2016<\/strong>: <strong>COMPRESS\/DECOMPRESS<\/strong> per la compressione, <strong>OPENJSON<\/strong> e <strong>JSON_VALUE<\/strong> per la lettura dei dati <em>JSON<\/em>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">COMPRESS\/DECOMPRESS<\/h3>\n\n\n\n<p>I metodi <strong>COMPRESS <\/strong>e <strong>DECOMPRESS <\/strong>utilizzano l&#8217;algoritmo di compressione <em>GZIP <\/em>per comprimere un campo, che pu\u00f2 essere, per esempio, <em>NVARCHAR <\/em>o <em>NTEXT<\/em>, in un campo <strong>VARBINARY(MAX)<\/strong> e viceversa.<\/p>\n\n\n\n<p>Nel nostro caso effettuiamo una compressione di un campo <em>NVARCHAR(MAX)<\/em> contente una stringa formattata in formato <em>JSON<\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>DECLARE @JsonString = '{ \"chiave\": \"valore\" }'\nINSERT INTO Tabella (CampoCompresso) VALUES (COMPRESS(@JsonString))\n<\/code><\/pre>\n\n\n\n<p>Per decomprimere il campo \u00e8 sufficiente utilizzare il metodo <strong>DECOMPRESS <\/strong>ed effettuare il <strong>CAST <\/strong>al tipo di dato che era in origine prima della compressione:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT CAST(DECOMPRESS(CampoCompresso) AS NVARCHAR(MAX)) FROM Tabella<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Preparazione della base dati<\/h2>\n\n\n\n<p>Vediamo ora un&#8217;esempio concreto su una base dati.<\/p>\n\n\n\n<p>Creiamo un nuovo database su <em>SQL Server 2016<\/em> o successivo ed al suo interno creiamo due tabelle: <strong>TabellaInChiaro<\/strong> e <strong>TabellaCompressa<\/strong>, utilizzando i due comandi:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CREATE TABLE &#91;dbo].&#91;TabellaInChiaro](\n\t&#91;Id] &#91;int] IDENTITY(1,1) NOT NULL,\n\t&#91;Json] &#91;nvarchar](max) NOT NULL,\n \tCONSTRAINT &#91;PK_TabellaInChiaro] PRIMARY KEY CLUSTERED \n(\n\t&#91;Id] ASC\n) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON &#91;PRIMARY]\n)\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>CREATE TABLE &#91;dbo].&#91;TabellaCompressa](\n\t&#91;Id] &#91;int] IDENTITY(1,1) NOT NULL,\n\t&#91;Json] &#91;varbinary](max) NOT NULL,\n\tCONSTRAINT &#91;PK_TabellaCompressa] PRIMARY KEY CLUSTERED \n(\n\t&#91;Id] ASC\n) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON &#91;PRIMARY]\n)<\/code><\/pre>\n\n\n\n<p>Entrambe le tabelle contengono due campi: un <strong>Id<\/strong> progressivo numerico ed un campo chiamato <strong>Json<\/strong>, che sar\u00e0 di tipo <strong>NVARCHAR(MAX)<\/strong> nella tabella con i dati in chiaro e <strong>VARBINARY(MAX)<\/strong> in quella con i dati compressi.<\/p>\n\n\n\n<p>Popoliamo ora le tabelle con molteplici dati utilizzando un ciclo <em>WHILE<\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>DECLARE @Tot INT = 100000;\nDECLARE @Indice INT = 0;\nWHILE @Indice &lt; @Tot\nBEGIN\n\tINSERT INTO TabellaInChiaro (&#91;Json]) VALUES ('\n\t\t{\n\t\t\t\"Nome\": \"Prodotto' + CAST(@Indice + 1 AS NVARCHAR(MAX)) + '\",\n\t\t\t\"Prezzo\": 15,\n\t\t\t\"Qta\": 50,\n\t\t\t\"Descrizione\": \"Descrizione del prodotto ' + CAST(@Indice + 1 AS NVARCHAR(MAX)) + '\"\n\t\t}\n\t')\n\tSET @Indice = @Indice + 1\nEND\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>DECLARE @Tot INT = 100000;\nDECLARE @Indice INT = 0;\nWHILE @Indice &lt; @Tot\nBEGIN\n\tINSERT INTO TabellaCompressa(&#91;Json]) VALUES (COMPRESS('\n\t\t{\n\t\t\t\"Nome\": \"Prodotto' + CAST(@Indice + 1 AS NVARCHAR(MAX)) + '\",\n\t\t\t\"Prezzo\": 15,\n\t\t\t\"Qta\": 50,\n\t\t\t\"Descrizione\": \"Descrizione del prodotto ' + CAST(@Indice + 1 AS NVARCHAR(MAX)) + '\"\n\t\t}\n\t'))\n\tSET @Indice = @Indice + 1\nEND\n<\/code><\/pre>\n\n\n\n<p>A questo punto abbiamo due tabelle che contengono i medesimi dati, da una parte in chiaro e dell&#8217;altra compressi.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Interrogazione<\/h2>\n\n\n\n<p>Per interrogare una stringa contenente informazioni formattate in formato <em>JSON<\/em>, <em>SQL Server<\/em>, come gi\u00e0 detto dalla versione <strong>2016<\/strong>, mette a disposizione diversi strumenti, tra cui: <strong>JSON_VALUE<\/strong> per estrarre un valore scalare da una stringa <em>JSON <\/em>e <strong>JSON_QUERY<\/strong> per estrarre invece un oggetto.<\/p>\n\n\n\n<p>E&#8217; possibile anche ottenere da un <em>JSON <\/em>un set di righe ed interrogarle come fossero comuni campi di una tabella <em>SQL<\/em>. Per fare ci\u00f2 si utilizza <strong>OPENJSON<\/strong>. <\/p>\n\n\n\n<p>Vediamo ora qualche esempio di interrogazione della nostra tabella con i dati in chiaro:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT JSON_VALUE(&#91;Json], '$.Nome') FROM TabellaInChiaro<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>1<\/td><td>Prodotto1<\/td><\/tr><tr><td>2<\/td><td>Prodotto2<\/td><\/tr><tr><td>3<\/td><td>Prodotto3<\/td><\/tr><tr><td>4<\/td><td>Prodotto4<\/td><\/tr><tr><td>&#8230;<\/td><td>&#8230;<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Questa <em>QUERY <\/em>mostra l&#8217;elenco dei nomi dei prodotti accedendo direttamente al campo <em>Nome <\/em>del <em>JSON <\/em>sfruttando il metodo <strong>JSON_VALUE<\/strong>.<\/p>\n\n\n\n<p>Lo stesso risultato lo otteniamo anche utilizzando il metodo <strong>OPENJSON<\/strong> per trasformare la stringa <em>JSON <\/em>in un set di dati:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT Nome FROM TabellaInChiaro CROSS APPLY OPENJSON(&#91;Json]) WITH (Nome NVARCHAR(MAX))<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>1<\/td><td>Prodotto1<\/td><\/tr><tr><td>2<\/td><td>Prodotto2<\/td><\/tr><tr><td>3<\/td><td>Prodotto3<\/td><\/tr><tr><td>4<\/td><td>Prodotto4<\/td><\/tr><tr><td>&#8230;<\/td><td>&#8230;<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Continuando ad utilizzare <strong>OPENJSON <\/strong>inseriamo qualche condizione:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT Nome, Prezzo, Qta FROM TabellaInChiaro\nCROSS APPLY OPENJSON(&#91;Json]) \nWITH (Nome NVARCHAR(MAX), Prezzo INT, Qta INT)\nWHERE Prezzo = 15\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><\/td><td><strong>Nome<\/strong><\/td><td><strong>Prezzo<\/strong><\/td><td><strong>Qta<\/strong><\/td><\/tr><tr><td>1<\/td><td>Prodotto1<\/td><td>15<\/td><td>50<\/td><\/tr><tr><td>2<\/td><td>Prodotto2<\/td><td>15<\/td><td>50<\/td><\/tr><tr><td>3<\/td><td>Prodotto3<\/td><td>15<\/td><td>50<\/td><\/tr><tr><td>4<\/td><td>Prodotto4<\/td><td>15<\/td><td>50<\/td><\/tr><tr><td>&#8230;<\/td><td>&#8230;<\/td><td>&#8230;<\/td><td>&#8230;<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Oppure qualche operazione:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT SUM(Prezzo), SUM(Qta) FROM TabellaInChiaro\nCROSS APPLY OPENJSON(&#91;Json]) \nWITH (Nome NVARCHAR(MAX), Prezzo INT, Qta INT)\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>1500000<\/td><td>5000000<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">E i dati compressi?<\/h2>\n\n\n\n<p>Niente di pi\u00f9 semplice, basta effettuare la decompressione del campo <strong>Json <\/strong>prima di passarlo come argomento ai metodi <strong>JSON_VALUE<\/strong> e\/o <strong>OPENJSON<\/strong>. Per esempio:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT JSON_VALUE(CAST(DECOMPRESS(&#91;Json]) AS NVARCHAR(MAX)), '$.Nome') FROM TabellaCompressa<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>1<\/td><td>Prodotto1<\/td><\/tr><tr><td>2<\/td><td>Prodotto2<\/td><\/tr><tr><td>3<\/td><td>Prodotto3<\/td><\/tr><tr><td>4<\/td><td>Prodotto4<\/td><\/tr><tr><td>&#8230;<\/td><td>&#8230;<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>O ancora:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT SUM(Prezzo), SUM(Qta) FROM TabellaCompressa\nCROSS APPLY OPENJSON(CAST(DECOMPRESS(&#91;Json]) AS NVARCHAR(MAX))) \nWITH (Nome NVARCHAR(MAX), Prezzo INT, Qta INT)\n<\/code><\/pre>\n\n\n\n<p>Gi\u00e0 eseguendo queste semplici <em>QUERY <\/em>si nota come il risultato non venga mostrato nell&#8217;immediato ma \u00e8 necessario qualche secondo in pi\u00f9 di elaborazione.<\/p>\n\n\n\n<p>Cerchiamo ora quindi di capire quali differenze ci sono in termini di prestazioni e in termini di dimensione del dato.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Qualche cifra&#8230;<\/h2>\n\n\n\n<p>Le cifre che seguono sono state calcolate utilizzando una base dati simile a quella degli esempi precedenti ma con una struttura <em>JSON <\/em>pi\u00f9 ricca di propriet\u00e0 e contenente oggetti nidificati.<\/p>\n\n\n\n<p><em>Hardware utilizzato per i test:<\/em><br>&#8211;<em> Laptop Lenovo X1 Carbon 6a generazione <\/em><br>&#8211; <em>Intel i7-8550U <\/em><br>&#8211; <em>16GB di memoria RAM LPDDR3 <\/em><br>&#8211; <em>SSD Samsung.<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Dimensioni<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>TabellaInChiaro (byte)<\/strong><\/td><td><strong>TabellaCompressa (byte)<\/strong><\/td><\/tr><tr><td>3368<\/td><td>227<\/td><\/tr><tr><td>3324<\/td><td>227<\/td><\/tr><tr><td>3324<\/td><td>225<\/td><\/tr><tr><td>3324<\/td><td>227<\/td><\/tr><\/tbody><\/table><figcaption>Dimensioni in byte di 4 record contenuti in entrambe le tabelle.<\/figcaption><\/figure>\n\n\n\n<p>Come si pu\u00f2 vedere, il <strong>record compresso \u00e8 del 93% circa pi\u00f9 piccolo<\/strong> rispetto al record non compresso.<\/p>\n\n\n\n<p>E quindi parlando di dimensioni totali della tabella:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>TabellaInChiaro (megabyte)<\/strong><\/td><td><strong>TabellaCompressa (megabyte)<\/strong><\/td><\/tr><tr><td>316<\/td><td>21<\/td><\/tr><\/tbody><\/table><figcaption>Dimensioni in megabyte dell&#8217;intera tabella.<\/figcaption><\/figure>\n\n\n\n<p><em>Le dimensioni dei singoli record e della tabella sono state ricavate utilizzando il metodo <strong>DATALENGTH<\/strong>.<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Prestazioni<\/h3>\n\n\n\n<p>Eseguiamo ora una semplice <em>QUERY SELECT<\/em> del <strong>Nome <\/strong>prodotto utilizzando il metodo <strong>OPENJSON<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT Nome FROM TabellaInChiaro\nCROSS APPLY OPENJSON(&#91;Json]) \nWITH (Nome NVARCHAR(MAX))\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>TabellaInChiaro (ms)<\/strong><\/td><td><strong>TabellaCompressa (ms)<\/strong><\/td><\/tr><tr><td>2704<\/td><td>7916<\/td><\/tr><\/tbody><\/table><figcaption>Lettura del dato in chiaro 66% pi\u00f9 veloce.<\/figcaption><\/figure>\n\n\n\n<p>Ora proviamo ad ottenere lo stesso elenco ma utilizzando il metodo<strong> JSON_VALUE<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT JSON_VALUE(&#91;Json], '$.Nome') FROM TabellaInChiaro<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>TabellaInChiaro (ms)<\/strong><\/td><td><strong>TabellaCompressa (ms)<\/strong><\/td><\/tr><tr><td>695<\/td><td>4933<\/td><\/tr><\/tbody><\/table><figcaption>Lettura del dato in chiaro 86% pi\u00f9 veloce.<\/figcaption><\/figure>\n\n\n\n<p>Si pu\u00f2 notare a colpo d&#8217;occhio come la <em>QUERY <\/em>che utilizza il metodo <strong>OPENJSON <\/strong>sia meno performante di quella che utilizza il metodo <strong>JSON_VALUE<\/strong>. Questo perch\u00e9 la stringa <em>JSON <\/em>con il primo metodo viene convertita in set di dati a differenza del secondo, dove si accede alla propriet\u00e0 <strong>Nome <\/strong>in maniera diretta e scalare.<\/p>\n\n\n\n<p>Proviamo ad effettuare ora una <em>QUERY <\/em>un po&#8217; pi\u00f9 complessa interrogando oggetti nidificati all&#8217;interno del <em>JSON<\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT P.Nome, P.Prezzo, P.Qta, T.Nome, T.Prezzo, T.Qta  FROM TabellaInChiaro\nCROSS APPLY OPENJSON(&#91;Json]) \nWITH (Nome NVARCHAR(MAX), Prezzo INT, Qta INT, SottoProdotto NVARCHAR(MAX) AS JSON) P\nCROSS APPLY OPENJSON(SottoProdotto)\nWITH (Nome NVARCHAR(MAX), Prezzo INT, Qta INT, SottoProdotto NVARCHAR(MAX) AS JSON) T\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>TabellaInChiaro (ms)<\/strong><\/td><td><strong>TabellaCompressa (ms)<\/strong><\/td><\/tr><tr><td>6279<\/td><td>12424<\/td><\/tr><\/tbody><\/table><figcaption>L&#8217;accesso ai dati compressi ha bisogno del doppio del tempo rispetto ai dati in chiaro.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusione<\/h2>\n\n\n\n<p>Trovare un&#8217;equilibrio tra prestazioni dell&#8217;interrogazione del dato e lo spazio che questo occupa sul disco non \u00e8 certamente semplice. Bisogna fare scelte, dettate anche da altre variabili, come ad esempio la quantit\u00e0 di volte che il dato deve essere interrogato oppure quali tipologie di interrogazioni vengono fatte pi\u00f9 spesso (esempio interrogazioni temporali).<\/p>\n\n\n\n<p>In questo articolo non c&#8217;\u00e8 la soluzione ma semplicemente una possibile strada da poter percorrere. Un&#8217;idea per migliorare la storicizzazione potrebbe per esempio essere una gestione ibrida dove i dati necessari per filtrare i record o con un alto numero di accessi vengono salvati in chiaro, mentre i restanti vengono compressi per evitare consumo inutile di spazio.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Link utili<\/h3>\n\n\n\n<p><a href=\"https:\/\/docs.microsoft.com\/it-it\/sql\/relational-databases\/data-compression\/data-compression?view=sql-server-ver15\">https:\/\/docs.microsoft.com\/it-it\/sql\/relational-databases\/data-compression\/data-compression?view=sql-server-ver15<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/docs.microsoft.com\/it-it\/sql\/relational-databases\/json\/json-data-sql-server?view=sql-server-ver15\">https:\/\/docs.microsoft.com\/it-it\/sql\/relational-databases\/json\/json-data-sql-server?view=sql-server-ver15<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Durante lo sviluppo di software basati su strutture dati relazionali complesse, spesso si ha la necessit\u00e0 di effettuare una storicizzazione del dato, che sia per utilizzi futuri, oppure ai fini di analisi o statistica.<\/p>\n<p>Pi\u00f9 la mole di dati \u00e8 consistente, pi\u00f9 ci si scontra con la necessit\u00e0 di trovare un equilibrio tra prestazione di interrogazione del dato e dimensione che questo occupa sul disco.<\/p>\n","protected":false},"author":3,"featured_media":3459,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"wds_primary_category":0,"footnotes":""},"categories":[130,139],"tags":[146,141,147,148,142,145,144,143,140,38],"class_list":["post-3448","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-insights","category-sql-server-insights","tag-compress","tag-database","tag-decompress","tag-gzip","tag-json","tag-json_query","tag-json_value","tag-openjson","tag-sql","tag-sql-server"],"_links":{"self":[{"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/posts\/3448","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/comments?post=3448"}],"version-history":[{"count":0,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/posts\/3448\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/media\/3459"}],"wp:attachment":[{"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/media?parent=3448"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/categories?post=3448"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/tags?post=3448"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}