<jupyter_start><jupyter_text>Uso dei Data CubeUtilizzeremo il pacchetto `cubes` che va installato con `pip` nel nostro ambiente. `cubes` comunica con un backend SQL, detto `Store`, che verrà creato con `sqlalchemy` fornisce l'astrazione necessaria per le creazione di diversi modelli di analisi (decsrizioni json del datacube, delle sue dimensioni, categorie e misure di aggregazione) all'interno di un _workspace_.![Architettura di `cubes`](https://cubes.readthedocs.io/en/v1.1/_images/cubes-workspace_simplified.png)La gerarchia delle dimensioni viene sostanziata in dei _mapping_ verso le misure fisiche dei fatti:![Gerarchia delle dimensioni](https://pythonhosted.org/cubes/_images/logical-to-physical.png)Il modello dei dati è strutturato come un file `json` che ha differenti proprietà mirate a descrivere gli aspetti del modello, dai metadati alla loro corrispondenza fisica con i dati presenti nel database:![Proprietà del modello](https://pythonhosted.org/cubes/_images/cubes-model_metadata.png)Segue una breve descrizione Modello logico- `name`: nome del modello- `label`: etichetta opzionale del modello- `description`: descrizione estesa opzionale del modello- `locale`: etichetta opzionale di localizzazione del modello (ad es. `'en'`, `'it'`, ...)- `cubes`: lista dei metadati dei cubi definiti nel modello- `dimensions`: lista dei metadati delle dimensioni- `public_dimensions`: lista delle dimensioni pubbliche che verrebbero esportate se definite. Tutte le dimensioni sono pubbliche per default Modello fisico- `store`: nome del data store in cui si trovano i dati: il nome di default è `Default`; si tratta della connessione al database utilizzato- `mappings`: dizionario delle corrispondenze tra i nomi logici delle dimensioni e quelli fisici delle colonne nel database che viene ereditata da tutti i cubi del modello- `joins`: specifiche di eventuali `join` utilizzati, per esempio con un backend `SQL` nella forma di una lista di `dict` che viene ereditata da tutti i cubi del modello- `browser_options`: eventuali opzioni passate al `browser`che è la struttura dati utilizzata per navigare i dati dei cubi. CubiEcco un esempio di cubo, con le proprietà di metadati, di dimensione e fisiche:```json{    "name": "sales",                // nome del cubo    "label": "Sales",               // etichetta    "dimensions": [ "date", ... ]   // array delle dimensioni come stringhe    "measures": [...],              // array delle misure che corrispondono alle colonne del database    "aggregates": [...],            // array delle misure di aggregazione    "details": [...],               // array degli attributi dei fatti che si vogliono eventualmente mostrare    "fact": "fact_table_name",      // riferimento esplicito alla tabella dei fatti                                     // che dev'essere usata dal backend    "mappings": { ... },            // mapping di colonne sulla tabella dei fatti    "joins": [ ... ]                // array dei join}``` Misure di aggregazioneLe funzioni di aggregazione sono gestite dal browser:![browser_aggregate](https://pythonhosted.org/cubes/_images/cubes-backend_browser.png)Ecco un esempio di definizione nel modello, ma la API consente la definizione di funzioni da parte dell'utente.```json"aggregates": [    {        "name": "amount_sum",        "label": "Total Sales Amount",        "measure": "amount",        "function": "sum"    },    {        "name": "vat_sum",        "label": "Total VAT",        "measure": "vat",        "function": "sum"    },    {        "name": "item_count",        "label": "Item Count",        "function": "count"    }]``` Join nel backend SQLIl beckend `SQL`accetta schemi a stella e snowflake:![](https://pythonhosted.org/cubes/_images/schema_star.png) ![](https://pythonhosted.org/cubes/_images/schema_snowflake.png)Il join dev'essere specificato esplicitamente per ottenere una rappresentazione tabellare unica di fatti e dimensioni con categorie e sotto-categorie:![](https://pythonhosted.org/cubes/_images/snowflake_schema.png)![](https://pythonhosted.org/cubes/_images/denormalized_schema.png)Ecco un esempio di specifica del join:```json"joins" = [    {        "master": "fact_sales.product_id",        "detail": {            "schema": "sales",            "table": "dim_products",            "column": "id"        }]```<jupyter_code># importiamo le librerie
import pymysql
from sqlalchemy import create_engine
from cubes.tutorial.sql import create_table_from_csv
from cubes import Workspace

# creiamo l'engine sql e il database fisico
engine = create_engine('mysql+pymysql://mysqluser:mysqlpassword@localhost:3306/data_cube',pool_pre_ping=True)
create_table_from_csv(engine,
                       "./Data/IBRD_Balance_Sheet__FY2010.csv", 
                       table_name="ibrd_balance",
                       fields=[
                             ("category", "string"),
                             ("category_label", "string"),
                             ("subcategory", "string"),
                             ("subcategory_label", "string"),
                             ("line_item", "string"),
                             ("year", "integer"),
                             ("amount", "integer")],
                       create_id=True
                   )<jupyter_output><empty_output><jupyter_text>Il workspace potrebbe essere creato a partire da un file di configurazione chiamato `slicer.ini` di default e che ha una sintassi simile alla seguente:```[workspace]model = model.json[store]type = sqlurl = postgresql://localhost/database```dove viene specificata la coppia store-workspace. In alternativa è possibile inizializzare il workspace direttamente dalla API.<jupyter_code># creiamo il workspace con le API

workspace = Workspace()
workspace.register_default_store("sql", url="mysql+pymysql://mysqluser:mysqlpassword@localhost:3306/data_cube")

# importiamo il modello del data cube che è definito come un file json
# in cui è definito il cubo "ibrd_balance"
workspace.import_model("./Data/tutorial_model.json")
# Creiamo un browser sul data cube per eseguire le operazioni

browser = workspace.browser("ibrd_balance")
# calcoliamo le misure di aggregazione previste dal modello
result = browser.aggregate()
result.summary["record_count"]
result.summary["amount_sum"]
result.aggregates
result = browser.aggregate(drilldown=[("year")])
for record in result:
    print(record)
result = browser.aggregate(drilldown=[("item",None,"subcategory")])
for record in result:
    print(record)
report=browser.aggregate(drilldown=[('item',None,'category'),'year'])
for record in report:
    print(record)
from cubes import Cell, PointCut

cut = [
    PointCut('year', [2010]),
    PointCut('item', ['l','dl'])
]

cell = Cell(workspace.cube('ibrd_balance'),cut)

report=browser.aggregate(cell,drilldown=[('item',None,'line_item')])

for record in report:
    print(record)
cell=Cell(workspace.cube('ibrd_balance'))

cell=cell.drilldown('year',2009)

facts = browser.facts(cell)

for fact in facts:
    print(fact)

report = browser.aggregate(cell,drilldown=[('item',None,'category')])

for record in report:
    print(record)

report.total_cell_count<jupyter_output>{'item.category': 'a', 'item.category_label': 'Assets', 'amount_sum': Decimal('275420'), 'record_count': 16}
{'item.category': 'l', 'item.category_label': 'Liabilities', 'amount_sum': Decimal('235383'), 'record_count': 11}
{'item.category': 'e', 'item.category_label': 'Equity', 'amount_sum': Decimal('40037'), 'record_count': 4}
{'fraction_non_alphanumeric': 0.11638448206905747, 'fraction_numerical': 0.005865884548726837, 'mean_word_length': 3.781389420012747, 'pattern_counts': {'":': 26, '<': 8, '<?xml version=': 0, '>': 8, 'https://': 8, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '507074', 'license': 'MIT', 'n_tokens_mistral': 2344, 'n_tokens_neox': 2240, 'n_words': 668, 'path': 'Data Cubes.ipynb', 'repo_name': 'fredff60/Big-Data', 'size': '7501'}