From 8f9314cddb3bbfbbe859cdee3b860d760609e811 Mon Sep 17 00:00:00 2001 From: 2211275 <2211275@stud.hs-mannheim.de> Date: Sat, 2 May 2026 21:28:41 +0200 Subject: [PATCH] coverage --- lego/graph.py | 212 ------------------ lego/lego_graph.ipynb | 115 +++++++--- lego/paper/KGR_paper1_lego.tex | 68 +++++- .../bilder/diagram_avg_part_price_brand.png | Bin 0 -> 13385 bytes lego/queries/avg_part_price_brands.csv | 6 + lego/queries/avg_part_price_brands.ods | Bin 0 -> 15696 bytes 6 files changed, 143 insertions(+), 258 deletions(-) delete mode 100644 lego/graph.py create mode 100644 lego/paper/bilder/diagram_avg_part_price_brand.png create mode 100644 lego/queries/avg_part_price_brands.csv create mode 100644 lego/queries/avg_part_price_brands.ods diff --git a/lego/graph.py b/lego/graph.py deleted file mode 100644 index 2d6fe8b..0000000 --- a/lego/graph.py +++ /dev/null @@ -1,212 +0,0 @@ -# %% [markdown] -# Build the Lego Knowledge Graph using the sources in `/data`. - -# %% -from rdflib import Graph, Namespace, XSD, OWL, RDF, RDFS, SKOS, URIRef, Literal -import pandas as pd -from datetime import datetime - -# %% [markdown] -# Setup the requirements for building a knowledge graph - -# %% -g = Graph() -thm = Namespace("https://thm.de/") -THM = Namespace("https://thm.de/ont/") - -# %% [markdown] -# # Rebrickable - -# %% [markdown] -# ![Rebrickable](\data\rebrickable\downloads_schema_v3.png) - -# %% -re_colors = pd.read_csv("data/rebrickable/colors.csv") -re_elements = pd.read_csv("data/rebrickable/elements.csv") -re_inventories = pd.read_csv("data/rebrickable/inventories.csv") -re_inventory_minifigs = pd.read_csv("data/rebrickable/inventory_minifigs.csv") -re_inventory_parts = pd.read_csv("data/rebrickable/inventory_parts.csv") -re_inventory_sets = pd.read_csv("data/rebrickable/inventory_sets.csv") -re_minifigs = pd.read_csv("data/rebrickable/minifigs.csv") -re_part_categories = pd.read_csv("data/rebrickable/part_categories.csv") -re_part_relationships = pd.read_csv("data/rebrickable/part_relationships.csv") -re_parts = pd.read_csv("data/rebrickable/parts.csv") -re_sets = pd.read_csv("data/rebrickable/sets.csv") -re_themes = pd.read_csv("data/rebrickable/themes.csv") - -# %% [markdown] -# Colors - -# %% -for color in re_colors.itertuples(index=False): - color_ref = thm[f"colors/{color.id}"] - - g.add((color_ref, RDFS.label, Literal(color.name, lang="en"))) - g.add((color_ref, THM.color, Literal(color.rgb))) - g.add((color_ref, THM.is_transparent, Literal(color.is_trans, datatype=XSD.boolean))) - - if not pd.isna(color.y1): - # First appearance - g.add((color_ref, THM.first_year, Literal(datetime(year = int(color.y1), month=1, day=1)))) - if not pd.isna(color.y2): - # Last appearance - g.add((color_ref, THM.last_year, Literal(datetime(year = int(color.y2), month=1, day=1)))) - - -# %% [markdown] -# Part Categories - -# %% -for part_category in re_part_categories.itertuples(index=False): - part_category_ref = thm[f"part_category/{part_category.id}"] - - g.add((part_category_ref, RDFS.label, Literal(part_category_ref, lang="en"))) - -# %% [markdown] -# Parts - -# %% -for part in re_parts.itertuples(index=False): - part_ref = thm[f"part/{part.part_num}"] - - g.add((part_ref, RDFS.label, Literal(part.name, lang="en"))) - g.add((part_ref, THM.part_category, thm[f"part_category/{part.part_cat_id}"])) - g.add((part_ref, THM.part_material, Literal(part.part_material))) - -# %% [markdown] -# Elements - -# %% -for element in re_elements.itertuples(index=False): - part_ref = thm[f"part/{element.part_num}"] - color_ref = thm[f"colors/{element.color_id}"] - - g.add((part_ref, THM.has_color, color_ref)) - -# %% [markdown] -# Part Relationships - -# %% -for part_relationship in re_part_relationships.itertuples(index=False): - part_ref_parent = thm[f"part/{part_relationship.parent_part_num}"] - part_ref_child = thm[f"part/{part_relationship.child_part_num}"] - - g.add((part_ref_parent, THM.has_child, part_ref_child)) - -# %% [markdown] -# Themes - -# %% -for theme in re_themes.itertuples(index=False): - theme_ref = thm[f"theme/{int(theme.id)}"] - - g.add((theme_ref, RDFS.label, Literal(theme.name, lang="en"))) - - if not pd.isna(theme.parent_id): - g.add((theme_ref, THM.parent_theme, thm[f"theme/{int(theme.parent_id)}"])) - -# %% [markdown] -# Sets - -# %% -for lego_set in re_sets.itertuples(index=False): - set_ref = thm[f"set/lego/{lego_set.set_num}"] - - g.add((set_ref, RDFS.label, Literal(lego_set.name, lang="en"))) - g.add((set_ref, THM.year, Literal(datetime(int(lego_set.year), 1, 1)))) - g.add((set_ref, THM.theme, thm[f"theme/{int(lego_set.theme_id)}"])) - g.add((set_ref, THM.num_parts, Literal(int(lego_set.num_parts), datatype=XSD.integer))) - g.add((set_ref, THM.brand, Literal("Lego"))) - -# %% [markdown] -# Minifigures - -# %% -for minifig in re_minifigs.itertuples(index=False): - minifig_ref = thm[f"minifig/{minifig.fig_num}"] - - g.add((set_ref, RDFS.label, Literal(minifig.name, lang="en"))) - g.add((set_ref, THM.num_parts, Literal(int(minifig.num_parts), datatype=XSD.integer))) - -# %% [markdown] -# Now the ugly part: Inventories - -# %% -for inventory in re_inventories.itertuples(index=False): - inventory_ref = thm[f"inventory/{inventory.id}"] - - g.add((inventory_ref, THM.set, thm[f"sets/lego/{inventory.set_num}"])) - -# %% [markdown] -# Inventories relate sets, minifigures and parts to each other, creating a kind of "top level set" -# (this takes a lot of time) - -# %% -for inventory_part in re_inventory_parts.itertuples(index=False): - inventory_part_ref = thm[f"inventory_part/{inventory_part.inventory_id}/{inventory_part.part_num}"] - - inventory_ref = thm[f"inventory/{inventory_part.inventory_id}"] - part_ref = thm[f"part/{inventory_part.part_num}"] - - g.add((inventory_part_ref, RDFS.domain, inventory_ref)) - g.add((inventory_part_ref, RDFS.range, part_ref)) - g.add((inventory_part_ref, RDF.type, RDF.Property)) - - g.add((inventory_part_ref, THM.quantity, Literal(int(inventory_part.quantity), datatype=XSD.integer))) - g.add((inventory_part_ref, THM.is_spare, Literal(inventory_part.is_spare, datatype=XSD.boolean))) - g.add((inventory_part_ref, THM.color, thm[f"color/{inventory_part.color_id}"])) - -# %% -for inventory_set in re_inventory_sets.itertuples(index=False): - inventory_set_ref = thm[f"inventory_set/{inventory_set.inventory_id}/{inventory_set.set_num}"] - - inventory_ref = thm[f"inventory/{inventory_set.inventory_id}"] - set_ref = thm[f"set/lego/{inventory_set.set_num}"] - - g.add((inventory_set_ref, RDFS.domain, inventory_ref)) - g.add((inventory_set_ref, RDFS.range, set_ref)) - g.add((inventory_set_ref, RDF.type, RDF.Property)) - - g.add((inventory_set_ref, THM.quantity, Literal(int(inventory_set.quantity), datatype=XSD.integer))) - -# %% -for inventory_minifig in re_inventory_minifigs.itertuples(index=False): - inventory_minifig_ref = thm[f"inventory_minifig/{inventory_minifig.inventory_id}/{inventory_minifig.fig_num}"] - - inventory_ref = thm[f"inventory/{inventory_minifig.inventory_id}"] - minifig_ref = thm[f"minifig/lego/{inventory_minifig.fig_num}"] - - g.add((inventory_minifig_ref, RDFS.domain, inventory_ref)) - g.add((inventory_minifig_ref, RDFS.range, minifig_ref)) - g.add((inventory_minifig_ref, RDF.type, RDF.Property)) - - g.add((inventory_minifig_ref, THM.quantity, Literal(int(inventory_minifig.quantity), datatype=XSD.integer))) - -# %% [markdown] -# Serialize the graph in turtle format - -# %% [markdown] -# ``` -# ___-------___ -# _-~~ ~~-_ -# _-~ /~-_ -# /^\__/^\ /~ \ / \ -# /| O|| O| / \_______________/ \ -# | |___||__| / / \ \ -# | \ / / \ \ -# | (_______) /______/ \_________ \ -# | / / \ / \ -# \ \^\\ \ / \ / -# \ || \______________/ _-_ //\__// -# \ ||------_-~~-_ ------------- \ --/~ ~\ || __/ -# ~-----||====/~ |==================| |/~~~~~ -# (_(__/ ./ / \_\ \. -# (_(___/ \_____)_) -# ``` - -# %% -g.bind("thmont", THM) - -g.serialize("lego_graph_rebrickable.ttl", format="turtle") - - diff --git a/lego/lego_graph.ipynb b/lego/lego_graph.ipynb index 8584a3d..75cb09f 100644 --- a/lego/lego_graph.ipynb +++ b/lego/lego_graph.ipynb @@ -10,13 +10,14 @@ }, { "cell_type": "code", - "execution_count": 105, + "execution_count": 257, "id": "90209948", "metadata": {}, "outputs": [], "source": [ "from rdflib import Graph, Namespace, XSD, OWL, RDF, RDFS, SKOS, URIRef, Literal\n", - "import pandas as pd" + "import pandas as pd\n", + "import numpy as np" ] }, { @@ -29,7 +30,7 @@ }, { "cell_type": "code", - "execution_count": 106, + "execution_count": 258, "id": "8e573135", "metadata": {}, "outputs": [], @@ -57,7 +58,7 @@ }, { "cell_type": "code", - "execution_count": 107, + "execution_count": 259, "id": "d8a1fe84", "metadata": {}, "outputs": [], @@ -86,7 +87,7 @@ }, { "cell_type": "code", - "execution_count": 108, + "execution_count": 260, "id": "ae505704", "metadata": {}, "outputs": [], @@ -117,7 +118,7 @@ }, { "cell_type": "code", - "execution_count": 109, + "execution_count": 261, "id": "fb9e17d6", "metadata": {}, "outputs": [], @@ -139,7 +140,7 @@ }, { "cell_type": "code", - "execution_count": 110, + "execution_count": 262, "id": "8fdb080e", "metadata": {}, "outputs": [], @@ -163,7 +164,7 @@ }, { "cell_type": "code", - "execution_count": 111, + "execution_count": 263, "id": "579b1d67", "metadata": {}, "outputs": [], @@ -193,7 +194,7 @@ }, { "cell_type": "code", - "execution_count": 112, + "execution_count": 264, "id": "00db079a", "metadata": {}, "outputs": [], @@ -216,7 +217,7 @@ }, { "cell_type": "code", - "execution_count": 113, + "execution_count": 265, "id": "1a529aae", "metadata": {}, "outputs": [], @@ -241,7 +242,7 @@ }, { "cell_type": "code", - "execution_count": 114, + "execution_count": 266, "id": "29b357ef", "metadata": {}, "outputs": [], @@ -267,7 +268,7 @@ }, { "cell_type": "code", - "execution_count": 115, + "execution_count": 267, "id": "a67b3e70", "metadata": {}, "outputs": [], @@ -290,7 +291,7 @@ }, { "cell_type": "code", - "execution_count": 116, + "execution_count": 268, "id": "0c97dc4d", "metadata": {}, "outputs": [], @@ -313,7 +314,7 @@ }, { "cell_type": "code", - "execution_count": 117, + "execution_count": 269, "id": "dc2ba03e", "metadata": {}, "outputs": [ @@ -323,7 +324,7 @@ "'\\nfor inventory_part in re_inventory_parts.itertuples(index=False):\\n inventory_part_ref = thm[f\"inventory_part/{inventory_part.inventory_id}/{inventory_part.part_num}\"]\\n\\n inventory_ref = thm[f\"inventory/{inventory_part.inventory_id}\"]\\n part_ref = thm[f\"part/{inventory_part.part_num}\"]\\n\\n g.add((inventory_part_ref, RDF.type, THM.PartInv))\\n g.add((inventory_part_ref, RDF.type, RDF.Property))\\n\\n g.add((inventory_part_ref, RDFS.domain, THM.Inventory))\\n g.add((inventory_part_ref, RDFS.range, THM.Part))\\n\\n g.add((inventory_ref, THM.contains, inventory_part_ref))\\n g.add((part_ref, THM.belongs, inventory_part_ref))\\n\\n g.add((inventory_part_ref, THM.quantity, Literal(int(inventory_part.quantity), datatype=XSD.integer)))\\n g.add((inventory_part_ref, THM.is_spare, Literal(inventory_part.is_spare, datatype=XSD.boolean)))\\n g.add((inventory_part_ref, THM.color, thm[f\"color/{inventory_part.color_id}\"]))\\n'" ] }, - "execution_count": 117, + "execution_count": 269, "metadata": {}, "output_type": "execute_result" } @@ -353,7 +354,7 @@ }, { "cell_type": "code", - "execution_count": 118, + "execution_count": 270, "id": "8715a1cf", "metadata": {}, "outputs": [], @@ -378,7 +379,7 @@ }, { "cell_type": "code", - "execution_count": 119, + "execution_count": 271, "id": "08c2c580", "metadata": {}, "outputs": [], @@ -419,7 +420,7 @@ }, { "cell_type": "code", - "execution_count": 120, + "execution_count": 272, "id": "1e0ac437", "metadata": {}, "outputs": [], @@ -438,7 +439,7 @@ }, { "cell_type": "code", - "execution_count": 121, + "execution_count": 273, "id": "fd944ccb", "metadata": {}, "outputs": [], @@ -468,7 +469,7 @@ }, { "cell_type": "code", - "execution_count": 122, + "execution_count": 274, "id": "307a3210", "metadata": {}, "outputs": [], @@ -479,9 +480,9 @@ " \n", " if (element_ref, None, None) in g:\n", " if not pd.isna(bs_element.BrickLinkSoldPriceNew):\n", - " g.add((element_ref, THM.price_new, Literal(bs_element.BrickLinkSoldPriceNew)))\n", + " g.add((element_ref, THM.price_new, Literal(bs_element.BrickLinkSoldPriceNew, datatype=XSD.float)))\n", " if not pd.isna(bs_element.BrickLinkSoldPriceUsed):\n", - " g.add((element_ref, THM.price_used, Literal(bs_element.BrickLinkSoldPriceNew)))" + " g.add((element_ref, THM.price_used, Literal(bs_element.BrickLinkSoldPriceUsed, datatype=XSD.float)))" ] }, { @@ -496,7 +497,7 @@ }, { "cell_type": "code", - "execution_count": 123, + "execution_count": 275, "id": "a8beb593", "metadata": {}, "outputs": [], @@ -508,7 +509,7 @@ }, { "cell_type": "code", - "execution_count": 124, + "execution_count": 276, "id": "bbf5462b", "metadata": {}, "outputs": [], @@ -527,7 +528,7 @@ }, { "cell_type": "code", - "execution_count": 125, + "execution_count": 277, "id": "ef52582e", "metadata": {}, "outputs": [ @@ -537,7 +538,7 @@ "'\\nfor bl_part in bl_parts.itertuples(index=False):\\n part_ref = thm[f\"part/{bl_part.part_id}\"]\\n\\n if not (part_ref, None, None) in g:\\n additional_entries += 1\\n g.add((part_ref, RDFS.label, Literal(bl_part.part_name, lang=\"en\")))\\n'" ] }, - "execution_count": 125, + "execution_count": 277, "metadata": {}, "output_type": "execute_result" } @@ -555,17 +556,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 278, "id": "8bf0ffeb", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'\\nfor bl_minifig in bl_minifigs.itertuples(index=False):\\n minifig_ref = thm[f\"minfig/{bl_minifig.minifig_id}\"]\\n\\n if not (minifig_ref, None, None) in g:\\n additional_entries += 1\\n g.add((minifig_ref, RDFS.label, Literal(bl_minifig.minifig_name, lang=\"en\")))\\n'" + "'\\nfor bl_minifig in bl_minifigs.itertuples(index=False):\\n minifig_ref = thm[f\"minfig/{bl_minifig.minifig_id}\"]\\n\\n if not (minifig_ref, None, None) in g:\\n g.add((minifig_ref, RDFS.label, Literal(bl_minifig.minifig_name, lang=\"en\")))\\n'" ] }, - "execution_count": 126, + "execution_count": 278, "metadata": {}, "output_type": "execute_result" } @@ -590,7 +591,7 @@ }, { "cell_type": "code", - "execution_count": 127, + "execution_count": 279, "id": "ab1ec488", "metadata": {}, "outputs": [], @@ -600,13 +601,54 @@ }, { "cell_type": "code", - "execution_count": 128, + "execution_count": 293, + "id": "9bcd2956", + "metadata": {}, + "outputs": [], + "source": [ + "t = me_sets[me_sets[\"brand\"] == \"Pantasy\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 294, + "id": "9ab21460", + "metadata": {}, + "outputs": [], + "source": [ + "t[\"ratio\"] = t[\"price_eur\"] / t[\"num_parts\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 295, + "id": "459c3a4c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "np.float64(0.43016261640379705)" + ] + }, + "execution_count": 295, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t[\"ratio\"].mean()" + ] + }, + { + "cell_type": "code", + "execution_count": 282, "id": "bfcf2840", "metadata": {}, "outputs": [], "source": [ "for me_set in me_sets.itertuples(index=False):\n", - " if not pd.isna(me_set.brand) or not pd.isna(me_set.id):\n", + " if not pd.isna(me_set.brand) and not pd.isna(me_set.id):\n", " set_ref = thm[f\"set/{me_set.brand}/{me_set.id}\"]\n", "\n", " g.add((set_ref, RDF.type, THM.Set))\n", @@ -617,7 +659,8 @@ " if not pd.isna(me_set.num_parts):\n", " g.add((set_ref, THM.num_parts, Literal(int(me_set.num_parts), datatype=XSD.integer)))\n", " g.add((set_ref, THM.brand, Literal(me_set.brand)))\n", - " g.add((set_ref, THM.price_new, Literal(me_set.price_eur, datatype=XSD.float)))" + " if not pd.isna(me_set.price_eur):\n", + " g.add((set_ref, THM.price_new, Literal(me_set.price_eur, datatype=XSD.float)))" ] }, { @@ -654,17 +697,17 @@ }, { "cell_type": "code", - "execution_count": 129, + "execution_count": 283, "id": "1a30bff8", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - ")>" + ")>" ] }, - "execution_count": 129, + "execution_count": 283, "metadata": {}, "output_type": "execute_result" } diff --git a/lego/paper/KGR_paper1_lego.tex b/lego/paper/KGR_paper1_lego.tex index 20f3219..c202bb1 100644 --- a/lego/paper/KGR_paper1_lego.tex +++ b/lego/paper/KGR_paper1_lego.tex @@ -49,7 +49,7 @@ %... then configure it. \fancyhead{} % clear all header fields \fancyhead[L]{Lego} - \fancyhead[R]{KGR - Knowledgegraphen} + \fancyhead[R]{KGR - Knowledge Graphen} \fancyfoot{} % clear all footer fields \fancyfoot[LE,RO]{\thepage} @@ -83,7 +83,7 @@ \subsection{Nutzen} - Wird ein Set an Klemmbausteinen nicht mehr vertrieben und man möchte das Set dennoch haben, so ergeben sich mehrere Möglichkeiten: + Wird ein Set an Klemmbausteinen nicht mehr vertrieben, an welchem dennoch Nachfrage besteht, existieren folgende Möglichkeiten: \begin{itemize} \item Man kauft das Set von einem Zweitanbieter \item Man stellt sich die benötigten Teile des Sets selbst zusammen. Dies geschieht entweder indem die Teile einzeln von Zweitanbietern gekauft werden oder durch den Erwerb von anderen Sets, welche die benötigten Teile enthalten. Siehe Fragen: \ref{item:min_set_count} und \ref{item:min_set_price}. @@ -211,17 +211,15 @@ https://thm.de/set/{brand}/{id} \label{fig:pipeline} \end{figure} - \section{Evaluation} \subsection{Ergebnis} Das Projekt kann unter der URL: \url{https://gitty.informatik.hs-mannheim.de/2211275/kgr} betrachtet werden. - Der resultierende Knowledge-Graph ist über 300 MB gross. + Der resultierende Knowledge-Graph ist über 300 MB gross. Die Dateigrösse lässt sich auf die Zuordnungen von Teilen zu Inventaren zurückführen. \subsection{Beispiel-Queries} Erhalten der Gesamtheit aller Lego Star Wars Minifiguren: - \begin{verbatim} SELECT DISTINCT ?name WHERE { @@ -237,7 +235,7 @@ WHERE { ?minifig rdfs:label ?name. } \end{verbatim} - Welche Minifiguren kommen am häufigsten vor? + Anzahl aller Minifiguren enthalten in allen Lego-Sets gruppiert nach Figur. \begin{verbatim} SELECT (SUM(?quantity) as ?sum) ?minifig ?name @@ -251,7 +249,7 @@ WHERE { GROUP BY ?minifig ?name ORDER BY DESC(?sum) \end{verbatim} - Durchschnittliche Anzahl an Teilen je Set gruppiert nach Jahren + Durchschnittliche Anzahl an Teilen je Set gruppiert nach Jahren. \begin{verbatim} SELECT ?year (AVG(?part_count) as ?avgp) WHERE { @@ -259,18 +257,68 @@ WHERE { ?set thm:num_parts ?part_count. } GROUP BY ?year -ORDER BY DESC(?avgp -) +ORDER BY DESC(?avgp) + \end{verbatim} + Durchschnittlicher Teilepreis gruppiert nach Marken. \label{verb:ppp_query} + \begin{verbatim} +SELECT ?brand (AVG(?price)/AVG(?num) as ?t) +WHERE { + ?set thm:num_parts ?num. + ?set rdfs:label ?name. + ?set rdf:type thm:Set. + ?set thm:brand ?brand. + ?set thm:price_new ?price. + FILTER (?num > 0) +} +GROUP BY ?brand +ORDER BY DESC(?t) \end{verbatim} \subsection{Abdeckung} - + Tabelle \ref{tab:coverage} zeigt einen Überblick welche der Prädikate (Graph, Name, Kategorie, Preise, Jahr) der Knowledge Graph für Minifiguren (Figs), Teile und Sets abdeckt (X=enthalten,-=Fehlt). Das Prädikat \textit{Graph} spiegelt wider, ob das Prädikat im Graph vorhanden ist. + \begin{table}[H] + \centering + \begin{tabular}{@{}lllllll@{}} + \toprule + & \multicolumn{3}{l}{Lego} & \multicolumn{3}{l}{Andere Marken} \\ \midrule + & Figs & Teile & Sets & Figs & Teile & Sets \\ \midrule + Graph & X & X & X & - & - & X \\ + Name & X & X & X & - & - & X\\ + Kateg. & - & X & X & - & - & - \\ + Preise & - & X & X & - & - & X \\ + Jahr & - & - & X & - & - & X \\ \bottomrule + \end{tabular} + \caption{Abdeckung des Graphen für Lego und weitere Klemmbausteinmarken} + \label{tab:coverage} + \end{table} + Da Lego keine IDs für Minifiguren vergibt ist das erkennen zweier gleichartiger Figuren schwieriger. Die Preise von \textit{Brickset} konnten nicht den Minifiguren aus \textit{Rebrickable} zugeordnet werden. Da \textit{Rebrickable} die Zuordnung von Minifiguren zu Sets liefert, wurde die Entscheidung getroffen auf die Preiszuordnung zu verzichten. Für Figuren und Teile weiterer Marken, waren eine Zuordnung nur schwer bis gar nicht möglich. Diese Zuordnung wäre beispielsweise durch Bilderkennung, anhand vom Hersteller bereitgestellte Bauanleitungen in Form von .PDF-Dateien möglich. \subsection{Konsistenz} \subsection{Qualität} + Es wird betrachtet, ob die ursprünglichen Fragestellungen mithilfe des Knowledge Graphen beantwortet werden können. + + \begin{enumerate} + \item Was ist die minimale Anzahl an Sets, die benötigt wird um ein anderes Set zusammenzubauen? + \item Was ist der geringste Preis einer Auswahl an Sets um ein anderes Set zusammenzubauen? + \item Sind Sets von anderen Herstellern im Vergleich zu Lego Sets, auf den durchschnittlichen Teilepreis betrachtet billiger?\\ + \textit{Diese Frage kann mithilfe der letzten Beispiel-Query \ref{verb:ppp_query} beantwortet werden. + \begin{figure}[H] + \centering + \includegraphics[width=\columnwidth]{./bilder/diagram_avg_part_price_brand.png} + \caption{Hersteller sortiert nach durchschnittlichem Teile-Preis} + \label{fig:ppp} + \end{figure} + } + \item Haben neuere Sets im Vergleich zu älteren Sets eine geringere Teileanzahl, da auf eine grössere Anzahl an speziell angefertigten Teilen zugegriffen werden kann? + \item Haben Sets mit höherer Teileanzahl eine höhere Anzahl an Minifiguren? + \item Welche anderen Sets, können mit Sets, die sich schon im eigenen Besitz befinden zusammengebaut werden? + \item Welche Lego-Teile besitzen äquivalente Teile von anderen Marken?\\ + \textit{Der Knowledge Graph bietet keine Möglichkeit dies zu beantwortet, da keine Datensätze über Teile, die nicht von Lego produziert worden sind, in die Erstellung des Graph eingeflossen sind.} + \end{enumerate} + \section{Ausblick} \section*{Abkürzungsverzeichnis} diff --git a/lego/paper/bilder/diagram_avg_part_price_brand.png b/lego/paper/bilder/diagram_avg_part_price_brand.png new file mode 100644 index 0000000000000000000000000000000000000000..e1fb2ac98a0525de38fd25537e77a30ccec82944 GIT binary patch literal 13385 zcmc(GcT`jB+Gi|?ipcSRApIN_kdE{spdz3MM0yP<9VwAO=*4ox0|*?tNS96^NDYLl zi1c0}C4?4wD51A7Z#;Kq?)_%Xth?r$@&}8ou*2T_-S6{j&y$cR+UoQd*)BpL5c)?C zALv3Lr(qDtDgE>3z&l*FA%Wo6g%=M^+#!(5&EV(jsq@0VvJl8`kVg;h>3b)W@X$Xu zEm8@Gk#>Q4INON9iID2Ve;8s$j%X#@Zi$ML4_Q9siHhN+*PwCG(MrrYx zc(aj{w3x+zH`4A8vtP9R(vu;moSL3_vnj>q^liM#Ojq;A-lQ?D0UKA^)Um{n)%&Hw zW2GJ2Er__~CR)pTc&q=X&{i^)BpL8^t=n7mDQe!WF-pA z@Zwr!5!d~WU?UGBtha88ZrnqfsBZ7>O(30}38&emg0zQ&u8%Z1jeFBW_db%NI#WHB z@ail4N@Xp3;|XiT4GWod#4jFGBNqnltLmIQBGRPf(rI=lh8Qpz26&Y;3XJ*_oNu4#sz%OL{-vw)TR zw7elXDr#m+67NrP%zM@|aw6v+8{DI~ehHk9=2pWm17do;)zCGX*d9r|X?gY8-02+x z|3`RPnY~T%6!w}G6Mg*=z z$wqdgv8SW1YRNac)MQ)UsKsZa+LSbdK9;#eFMVlbEhsz*DMSgpEL)kheJMCP?Us0r zg|DS&nb$^l&j_A0LK){q$d~W7$0PNZ9i}+jtrZI`HoL6@w&Xv~e$?XG$5-GI!;7Up#2*T%A8>s> z@xM91j%L6m!1wCL?ySfiM!F0vx8L-^H$@V@q(vT6?@_tg{=7HaS(vv^PMM!&wH>y< zHa<5x@*JDMU^(I+)F*a1 z`?LPxs2JJ4Anxp4^K@(~Et0mJ)|>Y{c3oi4h{ehBxz-omOa=5{m#s1V z5b2t0e!YLKLW93_JqP!X)Lf(OZycWq$CjTB6sL%4h#FLwpe5VHps$uc3^rbYX^Lw( z&`2_fZ*eUgt4)zFO)rxg#9hd;nfT?bOD&XPw4qwxn7%|&TIWRR%Rtlk{AQn;-^-cb z7QWJvU;Z8j+rDEEUlh`j(WpvkwL@zu>FqqIkq=)|3@Y#qt_yCQ`LOl`S%~7OtO(c* zhMKh)D)k?%n+@Q@-r;!;dU2ntPTAg=bh1XD!=S_sgq2^s(F;&|>3PLtikRmc{`K)@ zYiPkNkxwtMdMH=ac+R96whygF4OcHIwbA7*qGeJt27(^w9Q-fbIQDwHj`$T6L_@_3}dFi<&@EL`h49 zAR+JDH`^YZ5RM!gbYK;uRUmpqJKM*Zn@YQ~e<5OfAi!c2A5?!lCFECcx_2ku$FQO% z9HZ}Lt!9{e|tdX$qxFw?7w%C?W64G3Aw>R=(v64Xynn>Q& z^+6pxZ*3u&b=eLs%9_TL8N0@+;_weNjv`)1WZuo_zb?`+E`M)iPR!s6LFe6ALdxTu zGT$^A%b9y@%Q~AS0lHl+2Z1e<{7c^N57!7Jv#a=r+Q;s>;+T~W5^L~^3`=dVDd!`d zcaFb14PR8o&u1>WpQIZ>?g;1J3Y{Jd2Q(z>PO$a9^8bdYsAsWf_ApV6xRHAhvI1+) zoI~tC%rOMa#hz3&EXU41f1}LQUd@#7D+E$&XwT$9WJ^qqWflm%-+ZU9+`jyZXpu(b z`{X3_uR%_4HTnKBLaBe*E=>hssAq~6oYTmuGk9Wm1Nq(PBMY%IpC!-TewG%{@|(>I zSh87o+%55;HCM|wVgq~9aDhTIdi`%KW2o_ZXPsNFg?u=Yv4)|7PS7s`>;!=X8+h8fl*=qK;5il-nit@q+A_pb&VjuGl{()NrV)iCHs zMOeUoYaXMwMwqc(1*4CG*K|QmVr)ZGk_>!nhcs41jA_eqlY>CKEqG(v>M(LiQ>xYY zqO5KI_%_SOrSgA;SDry5_?8Y-@P%s+5(#mFMlkpdH{~?Pf^ZHo2xMI#MW+{;AsCeR z<+&>@eQ?IPfZf!qCaQJ$(ff9dJde;KXn%Uzuzd_7{2WSwxyv?B=+A^#Y2j!1L)eyp z{weO-KMO+)Ve)I!^|UodS(gi#Wr;V+J{Ee&?K`U9_ z|A*DozgG$mqp4a(mKe#(ALL-d4mNMp%4ob{A0j0)uU?$HO$f&tz9R+1Aj_ZWbkX61 ztd@=zOkf{_OT#sfMbhj*pPH9O1akYlJ8Dj7rdqY>#Kty4UF=W58=q9$L(;b z?)&tHg0^&K@f9*`2O-zX3iU&j2etIhfVIjvkF}^XFUv1Ro0-je5*-UnC?86rXA73? ziCF)f&b4+If#LELKCL7{8px#T^#$K;L|3VGEG)4bK`hIkeT1=#8?aq{INnZObNfHi z>7d{1s-l%S3Zo}o3e&l==v(@0tP%&ZC$U0KB3JERS((LksIy%%a|Xg)Shg(PsR!>C z-kixv+`(CA4$0eF69ZOH`*WEikNE_acWm{b_i}xYWfC-0+RWao50mR=ccjisgu~q* zscnGzH*)b3rvKHFGAhdpfryT=(!hv#H;u61ni;mgQ6akMH>)5;P!zf4=0=@yntrHf zrHA7*d(J?kg-zy0_ejR&l0MA8EagQ{B;8jP!e8p(5W{Hpk8=Kj4H#+m+__)oR(Ww4 zfFf;k^#{JUYkbYMmAB{(_S$OmUqsz>+%GP^uE|hjZ*jBU^5(K2odI#+bB4%U)qp;w zv>?jV}PVaVgd32j!cPHdJXlKluHyYD|#CF`Nsm`VI`u!uA9Dn%Wa zYXWR#hN%$Ok~7+CK*;I0I$y%r`WVH3L;4+$pYHQR+KI*U09V$jxS~%U(eEd^Ew|Z^ z)>YP)6(24zCkKyV1P-*E-cNs${k%d!hGD0_82bjtZPI$^fy9fR))C13{I zX48*w0*-~fn|A?GlPalzP;@n#SdF74(Cp21vDXD0dOGdfh&!5J26vV4&LcV*s+}-~ z_w~?H>R44KHBR`NBW1XuWyy}mN?xZD{h zvU!T%d_Ma!XH;K`quCIDTITi}PgJM11u#sqbn}cJ23{>b_j0icu7xO{+DqQ#C=)Hi zkC8SU>JbAve?4llI4+SqTz30!5P~D0tE>C_l%4#c;bsFb#9O)-58x+S2cjoLhat@O z4|*5?a-)iq3WqiJF%Khaj@RGm7JDrj-kE>~2?UVa^36^`8jq9v)~^Hj*;M^M<<|Z^ zeEAm}>22pc+v--3*19T~-)a&Ey9%?cKM1km0dQJ}uIFZVaXAC=zVljSlC@1;O)(q5 zjOuM8aZ=lRa!&M50<|6S`Q+G>C-j_&Wr)0FpSq{(&0qH8jwWuHr3A>392o;~OJ^B_ zp7(=;r@=h~|JtL59xI7`kaK`H_{oT_w2J#h-!;kwMsdG&O4j2A_}c_7-^mVZ)QBb^ zlgwTy7&2cT^kNyh%w%URWk?69VgZ*k(kj()r>I%Q)hJNf={(l1y%s$jcF=BT#uFEL z?jvtsX@X#y?XE)%3Z0gpVG3zfOfl)L5Nyf5rxa}x54+SMR1h*uhDpEk+98e?5W#J)#Xapq8nnIct|M3GJb*#g9e`XQb-0b#Tt$Az7LW}?2laYQ{5OnM zE0W_sJp?}17J`wP|E{+5zF4xDY@;js#2!9N%VDI%=3v}IG|eM=3~g49hY9XCeOX%j z{{7N0Qa^b{vlXSQRf@99}Do5l!;FC~qM8qbs}r3E6Y@v@IA}*d z5PiJegET3xx!OBl<~-w`;uP=V&&%*^dK4Dk-?e@U34v55YxN?%BRXIq--x801eq}Z z1a=s6<;vBuB=?wQi~Y7nW+N7(`rtRJB2UqMPwRF)47TnYQJ%bMmVK(!|MVJq-qmG$ z)DZb`+x(lqWN&Xn|67zmnp@nA!DZ;M@7q%lh8-%p92u)>$FVbu26}nKFo)uEM*whe zZ&8j9zawMXW*t5IC)Je?3bNpwMU+bajb@gEy&20?ENjcgc2Igx;4x;%?ewF5nZPx_ zgEy9%l8FxwrW*R;Cn}3&JtwJwkNa^aU+fRI39ETR2lU4iyOg^PA2iF4&K|EHw%2bU zj|nj$fhCn;JzEM5_!tRup?%JPoqgOkUrY$)!AVX1t{*|C$4y`AF5&QvCC9e=1xRu8 z$XS>xF2?R%{I*wdIh7sf>`EGMY4{^u3#Y3D;q%(&Bvj>USCWkH;SOn-4B)ToDBpj- zLmh=RNDDm3SK6N)ERs#d!07^VecpyvT!n8}ItW!~9!-rMuPQ5NWkc3|6=$usoP${y zI^0Z{wxxNKJEfAiqJ?Tj=f4}^#vYEtIVPy$s1L9g?QE6MhsSSC(tj8>j2VBK?pDVL z2DzMbMadeEpQ==z|85@K{@NJz{7k+yKM!E%QL7Y$T3BnN+FgB&&4n z5ZiC1@`-b*+sAn96vp8~*e z9pQg+*dKHhnd{m-b5zm5d%U`qioFV<#zv?3){oa7pRA;%V6R4Q7QwH0oN5dZqki_^ z&ACh&us~Ru+=*oax;akPx7YTDy0%Ti$r`BI-faXcfMTZ?v#g6nt~nud!?7pa!5U%p z??qxi7#ph1RRIcvcr%Z(TTmY^th$Kw3-~YlvIuBGUp7v!<-*NJ&rDRz;3Ok5P5tHL&xo%!;9S|^pJ)m(! zM@`+oD$Cc>;MX_oTXP-N9P-Bn-BWigtJQM&vWHZssq%&)XQ}X0x3SS?fisYOgJ*79 zw$%oHaUAmEX}dL1buERjp2?#9VX2P#s{|2T_S6$a30-SONbPy`%UGbnbxl*s{U1f6 z>a~dBa5*1{cj|wzJOmLZxa1{TgWq`CfWgdgUHSAf7hO|lqM{ml2I^?OT3&kr$kvY? zPulI0WnQtYEC8>gmVB;rfM!xEZ{8!D{JPsvHxOX;j~`*g z0(gguD4auX*5j1u=mz7W)+XnB^UtTe(c@^Z$WlsbT)>F!bnQ)6)sW&TfvLy3=rOmP z_5KxnWQg9|5o0Y!TZl#Q4O*C?4hkcu+$=oNKUXxG)O1Q3A-&pKXyjzLTqQtb!3&Df zyUcU7-F`%Eb@)?Wt~2R-IzZ!D&Ui)3_?{z@&Ea_a9DVbtT4V44-itKlvmv07lZ&n! z77Ye|0kXewvu>9g%K#oOdM(bLFHzs`?-qsu@?VC0W?iV71xtR%CPb;+j5^o!`S*E^ z=xY5BG@&lrHNYaS`j__&*TURB_o3oI7K&}Uja$IxPL%dPKi}Wbud2e>jSmp9^Ri$n zhB?4{0xBybyTW$DT@uOX84Nk}*qEa|kN!|Sh&}xHQ^NYY>E3SF^@M#h z(h<=JdlJ}JZerqU4FigGCn-2g{<#abW%=l6vxh-wU+jcJV0pVm4hlRN$gI~Y+B*z7 z*;<>i4yxZS(rXB7iD#Z7`&UrBl%YpNLO@0Ox>xepTu6iG>Xj z-w$JgM`eSGI~f})(f%j#YrFNEZfxj=2FEJ-xuFu6K@tt_=ktqFl^{@*l8>XJ=wrm8;oBnorP&=@ zaQ^Xnn8NNz*MvA@F|J}1k@z4e)_sod8SwE=G8T!qM%WI7iCE6ZZO;)>+q6>$y~PbP zXdlMnhK4!aj8gJAjC0JEi(D@^_ELdEIjWuq>KW#xq&Md!<+Su^LSbGTt+2*H3mI<$ z3%?6vLfye|W6k_BGww?f#$FJT6`v9_Gl!gS$kk0Pc`5hRZaiOQZ9m<0?ro^CK+L9J zs0dy2>VW>qR19J6)eZ+T*B|XyK^6byg$)faE&Yzvkzro* z-vuIS$eyd;hG0V?wLY6_a6&!aR4GxDEkQX>G-%(!0JAgzRUYC?OQupmGfS@Pmze;f zprzc>{MEk#wbr)bgU5u4rJ@>mV%Aa1LGHoh14}|ZjGl2g;ds>VQAU5Wn3YoW;*s95 zw*|X=;Gto|VUGcl?TDRcbNiX?$ir^smBOV))Xrbp(KjxOqP;dJSQqXL>*1$iYY`I@ zy7&tF0!KNH#dbit*X9XH+(65%t%r>uez-+;)fNR*oA4T9OGLO?x zo$%jS7jo8||LiW1Znb&GGVP*+n=3kH*-1}%#S9a~_Is@zL!$WfpZ9R+{c4N-WC_1t zJg#`uWu>`azy^|V+9wuDJM)&54r)1899mV@_M$~cy>!eibHho}^Ll3JF)70AhToO- zPQ{xG^19apWv=r|1?FOt{J_5f!__D; z{JhsTQ-SL~Ak-H*3)Gy&;md|y7X0b->oFH#i%<`sKRa0wgaLz~bJiaU{)B~Vs?VUR zod>>ULtYxqM^YXhbbD#zLt74UC#DDe3EKFJcZ~ikQ!$C}Kje*XU%aW?)mcQQ(D^{5 zA(MH5I}&Z9dYI`A%25v#|9Yl0DpOTiV3aMIr=?<#@#y{wH+EWb^n*Yb6S-GKCdYxS8Yb?1 zT7a=W)(+4u&PID|O{p3kznYcpMue1Ut_e^h6z?mDE^%mrt4q{aoF&bJRnxvi@ipCL zRS+$jK4Oonvtuc%D`Nu=gDHpJws5*}ApHeq_>MhQMSNq&zasW@KYI#9Ozo_M7K4bd zQJZ<@m-1n!;m;GY2o80b1Xb$^3#RFqmtj%O=wMgZ zjvJ`3x=QP-Q*BPCPKR~YSIe&f4MJ-Y2Ly756C=1b`N>aX?gorDwg1e!8qH*Z&hMs= zY0H4TGV*{k9QV@qVP=qQ1U6~8xf)T{)s|Hy_F~-hB`ljiIcp98<>|a*76wiH0%h3Y>AO0X*)0jSKOpdJwB;4rS41^nc>| zK?IF1I7zxaA#;e<;tb?v0xDS@<@Pqz%H`Gcr`{C2h^wWiOO1F)eS_bbZJdm^PDIe| zry}~>YKCEE_mb>OfPR#Pss~-_ogN7zRuz?d?|i~Zh6#hJN(Ao!fhs)tFTZ3d_%L3> zK5rB?pmXJATvR@p2SwmU`A+zYvPw`y3RZIRFSJXEmtf;f=1)PqAAw^mkHV+yg`3XWZ zHJNzgf!+A5X#~RV;r7uyzU&f_Va%Y=W_kS~i_W}ABz5eNA7TQ znMBQq&n^9tfm;TT2=b=KF8kAAqFWm+4R??dT((LlT8~onWM*^%DVu3d;`>eDbsuF~ zloF9;sR#}r(kk!0;*B}+rE)j-$p-G`aS`JmNk+b zlXmnVrY%SwDN)J6zW|&ask@8lsp#nGU=lQs_4g=hd~ERHJ3Wy!9)eOFLi=pag-_H6 z)KvJ3CrXM030P9deFd&VxoLp~P$fB}AlH1Ds5bs}%VE1wJz}uO$t-Z&w#6(u3m&+c z1PpBwRa*?s^#=Bdh=_oDqWU+EjnM`v%fnGzL|~xrL%ue!Z0#gho+1z|-0*VJ88qW< zFyfI)(y+h@zvFsWXZtmXFE3E$1`#oY*R1NXZ$CntS1bX!Ojh9A?|25%b z9*~*6LG2rKm@zqZW`7lW;*27Im>9d+_ig#Y$>z6&uljFE9dXq5Xww%fN)f2|r3h7b zRslMzq5}G?n^v!l0sUyp!O#cNL!FDQ7jCuz)7$Zqk2?`@S$Hf#Fw;A=)q^8WaTFA8 zP;c39_@A}T?{!@{u|veu%BqVov-?xp9ZdsCngFo(hvYKTA4h}S^NF5xA~ghcqO-v< zOS&H#HqTj1->>1~tFGV%yC-GfXXGcL_Wv>R`(LJnFYN9m7|hBdsEHsy2tng*!`1fD z$cWBSjW#tDvirL>h)0VgZWO^m_sIe!aS`}KO{fOlRn-hDz z?Ni~)WG=e=GeIO`tiy$QiCjh<_BkKtqk8E+}~E*f>O2PBaeLabll3EJJGlm#!MMiVHx<71xuq zdn<|4;-4F90R;epi#tG9wz13(;61*`Rd#Zf?FX6A1GT^+lXnLCwP|OVYp95B%r4 zUiL974fWOI+3b4xINBU$zRz}m@-dq%RbVVTea&5jR>E9sXl` zQ0pG3S#Kmz@F*K5mbcTvQm%x8g<|2qU}m55t{dt|4m}aobufx5ItHb^Q0NO}7bI2m zKRn%}w#}7QAePGT&$VsxDp}6H|S-1P!7%q1{tOj?`EkKn7 zU~lU)y$uE7K3w91>E}>+YgiYmG(R_;v5o5q6bvu$3*)Z3^9-bRT4n#;gNz-^u}JTp zXk`Feiy5?4i2p+0F7>eC35RPS$wv{ivc3T&H(>y!HUbI_3zW~tg~Q_>m&&NTeN%5Z z#0%Qu24d9idKthM5bdvuPe$FuEDI(P=~Z*dHBLN3+gXc34VkItWt{^DIk5c^&1z85 zlwoq#00rX^y+2=6*j*cbr_JOm)ja zTk6URNJcIaJ7LdqYs4O|O)bX$1j;+!81M%PE)w_2Oz~0>1v)?2ARA7z|FRdY&S3uY67>lEHjxL9_#q$m(m^17Kb%y0ScR+({U zLmcp>_!0*Z72A7-1{JSjABaPbO@T2BbC+%kqlSP|?(&G!kH~SIB=O0%|Bw>%s^^s( zYi@sT;KIP;x;c>Tapail6|3wJDd>B7?KtjVa|AxVRss;al&sUs^GMAN3`iKy>=cDk zMo*7a(7YSE@d!kwE5`qgE~i=d!U=ofdNQZ3f<kpUAp_3kCC2_AK`W5BKacgzr z?TNh+zsvG5)}S(Lf7x$sUDS%}q`TTY%@^kz$?!qbyj463E|=k^;}=9#!Z?;)MQ{%E z(@K{+2(4)HSV^f~dG>cTP8y4XuZA&pN#5Hh?(=*fag=j&Ax!4nH-2p3dTfaio|d!8 zZMVU&r^Q*6Y%5ca;c|(NT$JdkfhZ94k9tomsmzwe(Ei#3%@Z5!uj^2&`e{W95y+(St4# zXL-owr*O$F)cl)OVHVOFI&G+C+oB~dPi`NNuPo+EoJ^Fz{g8Imh)CYQWO3fkez zAA=hUKd~qs`S`FtH;$yv#UQggT>Tw2!;nGhk${A4GDNhBR&{*pf!X%F zBz?l%UTPPca9A9~&yQ z4!!eY4^|1TV}}hB2tN#aY_?Gu9maNWMfT-TeTx@GI<8DS6yKLt)cD)CFC}?S_nFI| zw;MPggIT^bcXlL`gVd}PG-nAfgW=;|#0E}OC-eVU@vY^5Gb0wxe)>JVN&2e^;m9;) zj@TBsld{Yb{n|jU{cm)G`83C%-OAOwj9Ix|$c?F3kkISRr?CaFJWM!j-hW=l*Wm9- zE;l--2Yl75g!Uagd8D;t?Nc+M|5QtvDwv9dppr6*vxZ4lpps|Ii0wdYPZ6zBK(=5W z-(jzpPf?xvdj?|D^J8E)IkB{2;xkF~dBe_IyH8mu&)y{1{4j&A!W10Yn^j%BaisRK zALGzZ#0wLoRkrIjsMG^OQ$eAh8&3ms`j4b%q_vf7ajf~}+wm%4Ml7x_0Z1j*Lf_PJ z%H3zu!*$xM`2}__%`&mqE?Jo&*~>IEV7$G z4YM^^HAV_AVZ|+BUbq~a$~%7mm|dhm_|vr33R}jIPoIoxW{D2FFATqX>^r*hO?K-T z4~x_>??g(iIx{F@L2k}+Ds-spMcx?ja?$eNrLjIg32XH%kab z^S$T%J(krTu!vX<{(=lfBfMhUUt>lm#5keVr$6UeYHI!*!>@RaTt?*1r)K+VO6$U} z2^8Vw*e2?R&MdhNVYF1f*%oiCe>YSK)AErPeIoTu_W3o_SaX*&aXai9f94|G+J1zh zz;kiX=kE34-&xd)ReZ(`^DlR?+>U&fnVR!Rm%agKI7F0I3 zHySvLgV)DbM}P6zw~&5OLta*imY(QdEFhJ^_1-p395YU?Riv?4&C6l$;EF|N+Z75~ zmZc-d@SDzYD$xq>n3kQhCM5f60xjK^hJ1P5!_jAa918&2z-TyK~03$VQD^w?c>T>(AmFtmk|R;`D8A&WMz(|=lu#} zxsZc;hH?})QlyoxjYhLvC~bNn%yRlr*zaz^?waXZY%r0~3gh#{EDNt$bnXtt7*z{Y z%&>bqlCH(G+!+}b8}G0asY@w#jN-uOr#Ufuv0ww}zfO^lvBT+d@7lra=BFV-H|WvV z;bYa@*tk5Lch_fndC0H)#+Tj_7D{(=T)AX&WemvZKqH4rqzJoZ z*IFtCwEqT|#oemYT1DXN0w)&c+XTf1_KM_Bw?g$~PTO~@AEO;4Pnh=C+U1O4s^P^y620tzd*I&HlBRK0QNH(bk1k%P(K4 zBd6VwA@drV>JfUv>x^ARa<(xqS$fnWe4E7OMv}3&9p-jy2NIJbGSf|&a%dJAjjgCt zo|AjmEI{JoaOOY%MTAM!4t2E%Ysq$uVXJIJ=WwWkVC?N1cy~ca72`dYmlA(D`X?0& zw}AmQ?SX3$hX=hhlg*n=PuK{#OIX#x6&>2ZA65>?{i>^Q?ye?p)Te?19kS-6!^~7rQ zb&R(gEC@N7AUgS$!{NE|ljc=3z?fa+vxksfK>w4Ms<2i4h<^|O!ifiv{|?@EAD!kH zUp)LS!LCk&J)cU)DB`}RiEQtui`3z|E|Ax9yiccVGD;&{46#IGJQDFVJf(j8pA#kBRhC_|MW zCxqIz8}ZJ}MTMX!HNY*!iLH4O8E8>=#B$;xFQD8h*i(>oo6hX}j}pxAP&J+FNco7< zk1pzgaY}i`%+(|O>cM#Z1dkf0MF05D9iqxf6^UvuXdyLnsya-$u3&#OCLW43{md%= uZ+>s(-*8Z`BX1s4^4Wn~crjOc!ma5x&V5e&%>fXTkVmT85776YzWy(Fxb&a^ literal 0 HcmV?d00001 diff --git a/lego/queries/avg_part_price_brands.csv b/lego/queries/avg_part_price_brands.csv new file mode 100644 index 0000000..5622c32 --- /dev/null +++ b/lego/queries/avg_part_price_brands.csv @@ -0,0 +1,6 @@ +"brand","t" +"Lego","0.09687904" +"Cobi","0.07586302" +"Pantasy","0.05728256" +"MouldKing","0.05323224" +"BlueBrixx","0.043733075" \ No newline at end of file diff --git a/lego/queries/avg_part_price_brands.ods b/lego/queries/avg_part_price_brands.ods new file mode 100644 index 0000000000000000000000000000000000000000..8a13050134ad79228e9a8f586f5b8b7d2428ff74 GIT binary patch literal 15696 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