A complete example ontology for the Acme Shop e-commerce platform, demonstrating all features of the Magnowlia ontology framework.
owl: → <http://www.w3.org/2002/07/owl#>rdf: → <http://www.w3.org/1999/02/22-rdf-syntax-ns#>rdfs: → <http://www.w3.org/2000/01/rdf-schema#>xsd: → <http://www.w3.org/2001/XMLSchema#>skos: → <http://www.w3.org/2004/02/skos/core#>dct: → <http://purl.org/dc/terms/>b: → <https://acmeshop.example.com/ontology/business#>bv: → <https://magnowlia.com/ontology/business-vocabulary#>m: → <https://magnowlia.com/ontology/mapping#>t: → <https://acmeshop.example.com/ontology/tech#>m:Table
owl:Class
m:Column
owl:Class
m:BusinessView
owl:Class
m:mapsToTable
owl:ObjectProperty
m:mapsToColumn
owl:ObjectProperty
m:joinCondition
owl:DatatypeProperty
m:realizedBy
owl:DatatypeProperty
bv:Metric
owl:Class
bv:TimeDimension
owl:Class
bv:BusinessConstant
owl:Class
bv:timeDimension
owl:ObjectProperty
bv:dependsOnProperty
owl:ObjectProperty
bv:dependsOnRelationship
owl:ObjectProperty
bv:dependsOnConstant
owl:ObjectProperty
bv:constantValue
owl:DatatypeProperty
bv:sampleEnumValues
owl:DatatypeProperty
bv:enumValuesFrom
owl:ObjectProperty
bv:commonEnumType
owl:DatatypeProperty
bv:metricExpression
owl:DatatypeProperty
bv:metricTable
owl:ObjectProperty
bv:metricPreFilter
owl:DatatypeProperty
bv:metricSql
owl:DatatypeProperty
bv:metricCategory
owl:DatatypeProperty
t:order_summary_view
m:Table
t:customers
m:Table
t:products
m:Table
t:order_summary_view.order_id
m:Column
t:order_summary_view.order_date
m:Column
t:order_summary_view.order_total
m:Column
t:order_summary_view.order_status
m:Column
t:order_summary_view.customer_country
m:Column
t:order_summary_view.product_category
m:Column
t:order_summary_view.payment_method
m:Column
t:order_summary_view.currency
m:Column
t:order_summary_view.customer_type
m:Column
t:order_summary_view.is_test_order
m:Column
t:order_summary_view.customer_id
m:Column
t:order_summary_view.quantity
m:Column
t:order_summary_view.product_id
m:Column
t:customers.customer_id
m:Column
t:customers.customer_segment
m:Column
t:customers.customer_name
m:Column
t:customers.customer_email
m:Column
t:customers.customer_country
m:Column
t:customers.customer_type
m:Column
t:customers.created_at
m:Column
t:products.product_id
m:Column
t:products.product_name
m:Column
t:products.product_category
m:Column
t:products.product_price
m:Column
b:Order
owl:Class
b:Customer
owl:Class
b:Product
owl:Class
b:WholesaleCustomer
owl:Class m:BusinessView
b:InternalCustomer
owl:Class m:BusinessView
b:PremiumWholesaleCustomer
owl:Class m:BusinessView
b:ReturnedOrder
owl:Class m:BusinessView
b:CancelledOrder
owl:Class m:BusinessView
b:customerHasOrder
owl:ObjectProperty
b:orderForCustomer
owl:ObjectProperty
b:orderHasProduct
owl:ObjectProperty
b:productInOrder
owl:ObjectProperty
b:orderId
owl:DatatypeProperty
b:orderTotal
owl:DatatypeProperty
b:orderStatus
owl:DatatypeProperty
b:customerCountry
owl:DatatypeProperty
b:productCategory
owl:DatatypeProperty
b:paymentMethod
owl:DatatypeProperty
b:orderCurrency
owl:DatatypeProperty
b:customerType
owl:DatatypeProperty
b:customerId
owl:DatatypeProperty
b:orderQuantity
owl:DatatypeProperty
b:isTestOrder
owl:DatatypeProperty
b:productId
owl:DatatypeProperty
b:productName
owl:DatatypeProperty
b:productCategoryMaster
owl:DatatypeProperty
b:productPrice
owl:DatatypeProperty
b:customerSegment
owl:DatatypeProperty
b:customerName
owl:DatatypeProperty
b:customerEmail
owl:DatatypeProperty
b:customerCountryMaster
owl:DatatypeProperty
b:customerTypeMaster
owl:DatatypeProperty
b:customerCreatedAt
owl:DatatypeProperty
b:OrderDate
bv:TimeDimension
b:CustomerRegistrationDate
bv:TimeDimension
b:gbpToEurExchangeRate
bv:BusinessConstant
b:totalRevenueMetric
bv:Metric
b:orderCountMetric
bv:Metric
b:averageOrderValueMetric
bv:Metric
b:returnRateMetric
bv:Metric
b:uniqueCustomersMetric
bv:Metric
b:totalItemsSoldMetric
bv:Metric
b:revenuePerCustomerSegmentMetric
bv:Metric
b:newCustomerRegistrationsMetric
bv:Metric
| 1 | @prefix owl: <http://www.w3.org/2002/07/owl#> . |
| 2 | @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . |
| 3 | @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . |
| 4 | @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . |
| 5 | @prefix skos: <http://www.w3.org/2004/02/skos/core#> . |
| 6 | @prefix dct: <http://purl.org/dc/terms/> . |
| 7 | @prefix b: <https://acmeshop.example.com/ontology/business#> . |
| 8 | @prefix bv: <https://magnowlia.com/ontology/business-vocabulary#> . |
| 9 | @prefix m: <https://magnowlia.com/ontology/mapping#> . |
| 10 | @prefix t: <https://acmeshop.example.com/ontology/tech#> . |
| 11 | |
| 12 | # =========================================================================== |
| 13 | # ONTOLOGY HEADER |
| 14 | # =========================================================================== |
| 15 | |
| 16 | "ttl-uri"><https://acmeshop.example.com/ontology> a owl:Ontology ; |
| 17 | dct:title "Acme Shop Optimized Business Ontology" ; |
| 18 | dct:description "Business-facing ontology for Acme Shop e-commerce platform, optimized for clarity and mapped to the analytics data warehouse." ; |
| 19 | dct:created "2026-03-03"^^xsd:date ; |
| 20 | dct:modified "2026-03-03"^^xsd:date ; |
| 21 | dct:contributor "Magnowlia Platform Team" ; |
| 22 | owl:versionInfo "0.2.0"^^xsd:string ; |
| 23 | rdfs:comment "Design decisions: (1) order_summary_view is the primary fact table - a denormalized view joining orders, customers and products. Properties like customerCountry and productCategory have domain b:Order because they are only available through this view. (2) Constants are inlined in metric expressions; bv:BusinessConstant declarations serve as documentation. (3) Metrics use structured properties (metricExpression/metricTable) for single-table queries and metricSql for multi-table joins." . |
| 24 | |
| 25 | # =========================================================================== |
| 26 | # MAPPING-LAYER VOCABULARY |
| 27 | # =========================================================================== |
| 28 | |
| 29 | m:Table a owl:Class ; |
| 30 | rdfs:label "Table" ; |
| 31 | rdfs:comment "A physical database table or view." . |
| 32 | |
| 33 | m:Column a owl:Class ; |
| 34 | rdfs:label "Column" ; |
| 35 | rdfs:comment "A physical database column." . |
| 36 | |
| 37 | m:BusinessView a owl:Class ; |
| 38 | rdfs:label "Business View" ; |
| 39 | rdfs:comment "A business class backed by a filtered or composite database view." . |
| 40 | |
| 41 | m:mapsToTable a owl:ObjectProperty ; |
| 42 | rdfs:domain owl:Class ; |
| 43 | rdfs:range m:Table ; |
| 44 | rdfs:label "maps to table" ; |
| 45 | rdfs:comment "Links a business class to a physical table." . |
| 46 | |
| 47 | m:mapsToColumn a owl:ObjectProperty ; |
| 48 | rdfs:domain owl:DatatypeProperty ; |
| 49 | rdfs:range m:Column ; |
| 50 | rdfs:label "maps to column" ; |
| 51 | rdfs:comment "Links a business property to a physical column." . |
| 52 | |
| 53 | m:joinCondition a owl:DatatypeProperty ; |
| 54 | rdfs:domain owl:Class ; |
| 55 | rdfs:range xsd:string ; |
| 56 | rdfs:label "join condition" ; |
| 57 | rdfs:comment "SQL-like join/filter rule for composite or filtered business views." . |
| 58 | |
| 59 | m:realizedBy a owl:DatatypeProperty ; |
| 60 | rdfs:domain owl:ObjectProperty ; |
| 61 | rdfs:range xsd:string ; |
| 62 | rdfs:label "realized by" ; |
| 63 | rdfs:comment "SQL-like realization of a business relationship via technical tables." . |
| 64 | |
| 65 | # =========================================================================== |
| 66 | # BUSINESS VOCABULARY |
| 67 | # =========================================================================== |
| 68 | |
| 69 | bv:Metric a owl:Class ; |
| 70 | rdfs:label "Metric" ; |
| 71 | rdfs:comment "A time-series business metric computed from SQL expressions." . |
| 72 | |
| 73 | bv:TimeDimension a owl:Class ; |
| 74 | rdfs:label "Time Dimension" ; |
| 75 | rdfs:comment "A time column used for metric aggregation." . |
| 76 | |
| 77 | bv:BusinessConstant a owl:Class ; |
| 78 | rdfs:label "Business Constant" ; |
| 79 | rdfs:comment "A fixed numeric value used in calculations and conversions." . |
| 80 | |
| 81 | bv:timeDimension a owl:ObjectProperty ; |
| 82 | rdfs:domain bv:Metric ; |
| 83 | rdfs:range bv:TimeDimension ; |
| 84 | rdfs:label "time dimension" . |
| 85 | |
| 86 | bv:dependsOnProperty a owl:ObjectProperty ; |
| 87 | rdfs:domain bv:Metric ; |
| 88 | rdfs:range owl:DatatypeProperty ; |
| 89 | rdfs:label "depends on property" . |
| 90 | |
| 91 | bv:dependsOnRelationship a owl:ObjectProperty ; |
| 92 | rdfs:domain bv:Metric ; |
| 93 | rdfs:range owl:ObjectProperty ; |
| 94 | rdfs:label "depends on relationship" . |
| 95 | |
| 96 | bv:dependsOnConstant a owl:ObjectProperty ; |
| 97 | rdfs:domain bv:Metric ; |
| 98 | rdfs:range bv:BusinessConstant ; |
| 99 | rdfs:label "depends on constant" ; |
| 100 | rdfs:comment "Indicates that a metric depends on a business constant value used in its calculation." . |
| 101 | |
| 102 | bv:constantValue a owl:DatatypeProperty ; |
| 103 | rdfs:domain bv:BusinessConstant ; |
| 104 | rdfs:range xsd:decimal ; |
| 105 | rdfs:label "constant value" ; |
| 106 | rdfs:comment "The numeric value of a business constant." . |
| 107 | |
| 108 | bv:sampleEnumValues a owl:DatatypeProperty ; |
| 109 | rdfs:domain owl:DatatypeProperty ; |
| 110 | rdfs:range xsd:string ; |
| 111 | rdfs:label "sample enum values" ; |
| 112 | rdfs:comment "Sample permitted enum-like tokens for the attribute (repeatable)." . |
| 113 | |
| 114 | bv:enumValuesFrom a owl:ObjectProperty ; |
| 115 | rdfs:domain owl:DatatypeProperty ; |
| 116 | rdfs:range m:Column ; |
| 117 | rdfs:label "enum values from column" ; |
| 118 | rdfs:comment "Marks a property as an enumeration whose tokens are sourced from this column." . |
| 119 | |
| 120 | bv:commonEnumType a owl:DatatypeProperty ; |
| 121 | rdfs:domain owl:DatatypeProperty ; |
| 122 | rdfs:range xsd:string ; |
| 123 | rdfs:label "common enum type" ; |
| 124 | rdfs:comment "Indicates this property uses a well-known enum set (e.g., country, currency, boolean)." . |
| 125 | |
| 126 | # Metric-specific structured properties |
| 127 | bv:metricExpression a owl:DatatypeProperty ; |
| 128 | rdfs:domain bv:Metric ; |
| 129 | rdfs:range xsd:string ; |
| 130 | rdfs:label "metric expression" ; |
| 131 | rdfs:comment "Valid SQL aggregation expression for the metric SELECT clause." . |
| 132 | |
| 133 | bv:metricTable a owl:ObjectProperty ; |
| 134 | rdfs:domain bv:Metric ; |
| 135 | rdfs:range m:Table ; |
| 136 | rdfs:label "metric table" ; |
| 137 | rdfs:comment "Primary source table for the metric." . |
| 138 | |
| 139 | bv:metricPreFilter a owl:DatatypeProperty ; |
| 140 | rdfs:domain bv:Metric ; |
| 141 | rdfs:range xsd:string ; |
| 142 | rdfs:label "metric pre-filter" ; |
| 143 | rdfs:comment "Optional WHERE clause conditions applied before aggregation." . |
| 144 | |
| 145 | bv:metricSql a owl:DatatypeProperty ; |
| 146 | rdfs:domain bv:Metric ; |
| 147 | rdfs:range xsd:string ; |
| 148 | rdfs:label "metric sql" ; |
| 149 | rdfs:comment "Full parameterized SQL template. Overrides metricExpression+metricTable when present." . |
| 150 | |
| 151 | bv:metricCategory a owl:DatatypeProperty ; |
| 152 | rdfs:domain bv:Metric ; |
| 153 | rdfs:range xsd:string ; |
| 154 | rdfs:label "metric category" ; |
| 155 | rdfs:comment "Taxonomy path for sidebar categorization. A metric may have 0..N categories. Each value is a comma-separated hierarchy path (e.g. 'Revenue, Per Segment')." . |
| 156 | |
| 157 | # =========================================================================== |
| 158 | # TECHNICAL LAYER - TABLES |
| 159 | # =========================================================================== |
| 160 | |
| 161 | t:order_summary_view a m:Table ; |
| 162 | rdfs:label "order_summary_view" ; |
| 163 | rdfs:comment "Denormalized view joining orders, customers, and products. Primary fact table for order analytics." . |
| 164 | |
| 165 | t:customers a m:Table ; |
| 166 | rdfs:label "customers" ; |
| 167 | rdfs:comment "Customer master data including segmentation and demographics." . |
| 168 | |
| 169 | t:products a m:Table ; |
| 170 | rdfs:label "products" ; |
| 171 | rdfs:comment "Product catalog with categories and pricing." . |
| 172 | |
| 173 | # =========================================================================== |
| 174 | # TECHNICAL LAYER - COLUMNS |
| 175 | # =========================================================================== |
| 176 | |
| 177 | t:order_summary_view.order_id a m:Column ; |
| 178 | rdfs:label "order_summary_view.order_id" ; |
| 179 | rdfs:comment "Unique order identifier (PK)." . |
| 180 | |
| 181 | t:order_summary_view.order_date a m:Column ; |
| 182 | rdfs:label "order_summary_view.order_date" ; |
| 183 | rdfs:comment "Date the order was placed. Used as the primary time dimension for order metrics." . |
| 184 | |
| 185 | t:order_summary_view.order_total a m:Column ; |
| 186 | rdfs:label "order_summary_view.order_total" ; |
| 187 | rdfs:comment "Total order amount. Currency is indicated by the currency column; may be EUR or GBP." . |
| 188 | |
| 189 | t:order_summary_view.order_status a m:Column ; |
| 190 | rdfs:label "order_summary_view.order_status" ; |
| 191 | rdfs:comment "Current order fulfillment status: pending, confirmed, shipped, delivered, returned, cancelled." . |
| 192 | |
| 193 | t:order_summary_view.customer_country a m:Column ; |
| 194 | rdfs:label "order_summary_view.customer_country" ; |
| 195 | rdfs:comment "ISO country code of the ordering customer. Denormalized from customer master." . |
| 196 | |
| 197 | t:order_summary_view.product_category a m:Column ; |
| 198 | rdfs:label "order_summary_view.product_category" ; |
| 199 | rdfs:comment "Category of the ordered product. Denormalized from product catalog." . |
| 200 | |
| 201 | t:order_summary_view.payment_method a m:Column ; |
| 202 | rdfs:label "order_summary_view.payment_method" ; |
| 203 | rdfs:comment "Payment method used for the order: credit_card, paypal, bank_transfer, apple_pay." . |
| 204 | |
| 205 | t:order_summary_view.currency a m:Column ; |
| 206 | rdfs:label "order_summary_view.currency" ; |
| 207 | rdfs:comment "ISO currency code for the order amount (EUR, GBP)." . |
| 208 | |
| 209 | t:order_summary_view.customer_type a m:Column ; |
| 210 | rdfs:label "order_summary_view.customer_type" ; |
| 211 | rdfs:comment "Customer classification: regular, internal (staff), wholesale." . |
| 212 | |
| 213 | t:order_summary_view.is_test_order a m:Column ; |
| 214 | rdfs:label "order_summary_view.is_test_order" ; |
| 215 | rdfs:comment "Boolean flag indicating whether this is a test order that should be excluded from reporting." . |
| 216 | |
| 217 | t:order_summary_view.customer_id a m:Column ; |
| 218 | rdfs:label "order_summary_view.customer_id" ; |
| 219 | rdfs:comment "FK to customers table. Denormalized into the view for join-free access." . |
| 220 | |
| 221 | t:order_summary_view.quantity a m:Column ; |
| 222 | rdfs:label "order_summary_view.quantity" ; |
| 223 | rdfs:comment "Number of items in the order line." . |
| 224 | |
| 225 | t:order_summary_view.product_id a m:Column ; |
| 226 | rdfs:label "order_summary_view.product_id" ; |
| 227 | rdfs:comment "FK to products table. Identifies the product in the order." . |
| 228 | |
| 229 | t:customers.customer_id a m:Column ; |
| 230 | rdfs:label "customers.customer_id" ; |
| 231 | rdfs:comment "Customer unique identifier (PK)." . |
| 232 | |
| 233 | t:customers.customer_segment a m:Column ; |
| 234 | rdfs:label "customers.customer_segment" ; |
| 235 | rdfs:comment "Customer segment classification: Premium, Standard, New, Churned." . |
| 236 | |
| 237 | t:customers.customer_name a m:Column ; |
| 238 | rdfs:label "customers.customer_name" ; |
| 239 | rdfs:comment "Full name of the customer." . |
| 240 | |
| 241 | t:customers.customer_email a m:Column ; |
| 242 | rdfs:label "customers.customer_email" ; |
| 243 | rdfs:comment "Primary email address of the customer." . |
| 244 | |
| 245 | t:customers.customer_country a m:Column ; |
| 246 | rdfs:label "customers.customer_country" ; |
| 247 | rdfs:comment "ISO country code of the customer. Master data source for the denormalized order_summary_view.customer_country." . |
| 248 | |
| 249 | t:customers.customer_type a m:Column ; |
| 250 | rdfs:label "customers.customer_type" ; |
| 251 | rdfs:comment "Customer classification: regular, internal (staff), wholesale. Master data source for the denormalized order_summary_view.customer_type." . |
| 252 | |
| 253 | t:customers.created_at a m:Column ; |
| 254 | rdfs:label "customers.created_at" ; |
| 255 | rdfs:comment "Timestamp when the customer record was created (registration date)." . |
| 256 | |
| 257 | t:products.product_id a m:Column ; |
| 258 | rdfs:label "products.product_id" ; |
| 259 | rdfs:comment "Product unique identifier (PK)." . |
| 260 | |
| 261 | t:products.product_name a m:Column ; |
| 262 | rdfs:label "products.product_name" ; |
| 263 | rdfs:comment "Display name of the product." . |
| 264 | |
| 265 | t:products.product_category a m:Column ; |
| 266 | rdfs:label "products.product_category" ; |
| 267 | rdfs:comment "Category the product belongs to: Electronics, Clothing, Home & Garden, Sports, Books." . |
| 268 | |
| 269 | t:products.product_price a m:Column ; |
| 270 | rdfs:label "products.product_price" ; |
| 271 | rdfs:comment "Current list price of the product in EUR." . |
| 272 | |
| 273 | # =========================================================================== |
| 274 | # BUSINESS LAYER - CLASSES |
| 275 | # =========================================================================== |
| 276 | |
| 277 | b:Order a owl:Class ; |
| 278 | rdfs:label "Order" ; |
| 279 | rdfs:comment "A customer order placed on the Acme Shop platform. Backed by the order_summary_view which is a denormalized view joining orders, customers, and products." ; |
| 280 | rdfs:seeAlso "ttl-uri"><https://schema.org/Order> ; |
| 281 | skos:example "ORD-2025-001234, ORD-2025-005678" ; |
| 282 | m:mapsToTable t:order_summary_view . |
| 283 | |
| 284 | b:Customer a owl:Class ; |
| 285 | rdfs:label "Customer" ; |
| 286 | skos:altLabel "Buyer", "Account" ; |
| 287 | rdfs:comment "A registered customer of Acme Shop." ; |
| 288 | rdfs:seeAlso "ttl-uri"><https://schema.org/Person> ; |
| 289 | skos:example "Jane Smith, Acme Corporation" ; |
| 290 | m:mapsToTable t:customers . |
| 291 | |
| 292 | b:Product a owl:Class ; |
| 293 | rdfs:label "Product" ; |
| 294 | skos:altLabel "Item", "SKU" ; |
| 295 | rdfs:comment "A product available in the Acme Shop catalog." ; |
| 296 | rdfs:seeAlso "ttl-uri"><https://schema.org/Product> ; |
| 297 | skos:example "Wireless Mouse Pro, Organic Cotton T-Shirt, Standing Desk" ; |
| 298 | m:mapsToTable t:products . |
| 299 | |
| 300 | # --- Subclasses with filters --- |
| 301 | |
| 302 | b:WholesaleCustomer a owl:Class, m:BusinessView ; |
| 303 | rdfs:subClassOf b:Customer ; |
| 304 | rdfs:label "Wholesale Customer" ; |
| 305 | rdfs:comment "Customer purchasing in bulk at wholesale prices. Identified by customer_type = 'wholesale' in the order view." ; |
| 306 | m:mapsToTable t:order_summary_view ; |
| 307 | m:joinCondition "order_summary_view.customer_type = 'wholesale'"^^xsd:string . |
| 308 | |
| 309 | b:InternalCustomer a owl:Class, m:BusinessView ; |
| 310 | rdfs:subClassOf b:Customer ; |
| 311 | rdfs:label "Internal Customer" ; |
| 312 | rdfs:comment "Internal staff purchases. Typically excluded from revenue reporting. Identified by customer_type = 'internal'." ; |
| 313 | m:mapsToTable t:order_summary_view ; |
| 314 | m:joinCondition "order_summary_view.customer_type = 'internal'"^^xsd:string . |
| 315 | |
| 316 | b:PremiumWholesaleCustomer a owl:Class, m:BusinessView ; |
| 317 | rdfs:subClassOf b:WholesaleCustomer ; |
| 318 | rdfs:label "Premium Wholesale Customer" ; |
| 319 | rdfs:comment "High-value wholesale customers with premium pricing agreements. Identified by customer_type = 'wholesale' AND customer_segment = 'Premium'." ; |
| 320 | m:mapsToTable t:order_summary_view ; |
| 321 | m:joinCondition "order_summary_view.customer_type = 'wholesale' AND customers.customer_segment = 'Premium'"^^xsd:string . |
| 322 | |
| 323 | b:WholesaleCustomer owl:disjointWith b:InternalCustomer . |
| 324 | |
| 325 | b:ReturnedOrder a owl:Class, m:BusinessView ; |
| 326 | rdfs:subClassOf b:Order ; |
| 327 | rdfs:label "Returned Order" ; |
| 328 | rdfs:comment "Orders that were returned or refunded by the customer." ; |
| 329 | m:mapsToTable t:order_summary_view ; |
| 330 | m:joinCondition "order_summary_view.order_status = 'returned'"^^xsd:string . |
| 331 | |
| 332 | b:CancelledOrder a owl:Class, m:BusinessView ; |
| 333 | rdfs:subClassOf b:Order ; |
| 334 | rdfs:label "Cancelled Order" ; |
| 335 | rdfs:comment "Orders that were cancelled before fulfillment. NOTE: Mutually exclusive with ReturnedOrder - an order is either cancelled or returned, not both." ; |
| 336 | rdfs:seeAlso b:ReturnedOrder ; |
| 337 | m:mapsToTable t:order_summary_view ; |
| 338 | m:joinCondition "order_summary_view.order_status = 'cancelled'"^^xsd:string . |
| 339 | |
| 340 | b:ReturnedOrder owl:disjointWith b:CancelledOrder . |
| 341 | |
| 342 | # =========================================================================== |
| 343 | # BUSINESS LAYER - RELATIONSHIPS |
| 344 | # =========================================================================== |
| 345 | |
| 346 | b:customerHasOrder a owl:ObjectProperty ; |
| 347 | rdfs:domain b:Customer ; |
| 348 | rdfs:range b:Order ; |
| 349 | rdfs:label "customer has order" ; |
| 350 | owl:inverseOf b:orderForCustomer ; |
| 351 | m:realizedBy "customers.customer_id = order_summary_view.customer_id"^^xsd:string . |
| 352 | |
| 353 | b:orderForCustomer a owl:ObjectProperty ; |
| 354 | rdfs:domain b:Order ; |
| 355 | rdfs:range b:Customer ; |
| 356 | rdfs:label "order for customer" ; |
| 357 | owl:inverseOf b:customerHasOrder ; |
| 358 | m:realizedBy "order_summary_view.customer_id = customers.customer_id"^^xsd:string . |
| 359 | |
| 360 | b:orderHasProduct a owl:ObjectProperty ; |
| 361 | rdfs:domain b:Order ; |
| 362 | rdfs:range b:Product ; |
| 363 | rdfs:label "order has product" ; |
| 364 | owl:inverseOf b:productInOrder ; |
| 365 | m:realizedBy "order_summary_view.product_id = products.product_id"^^xsd:string . |
| 366 | |
| 367 | b:productInOrder a owl:ObjectProperty ; |
| 368 | rdfs:domain b:Product ; |
| 369 | rdfs:range b:Order ; |
| 370 | rdfs:label "product in order" ; |
| 371 | owl:inverseOf b:orderHasProduct ; |
| 372 | m:realizedBy "products.product_id = order_summary_view.product_id"^^xsd:string . |
| 373 | |
| 374 | # =========================================================================== |
| 375 | # BUSINESS LAYER - PROPERTIES (Dimensions) |
| 376 | # =========================================================================== |
| 377 | |
| 378 | b:orderId a owl:DatatypeProperty ; |
| 379 | rdfs:label "Order ID" ; |
| 380 | rdfs:domain b:Order ; |
| 381 | rdfs:range xsd:string ; |
| 382 | rdfs:comment "Unique order identifier." ; |
| 383 | m:mapsToColumn t:order_summary_view.order_id . |
| 384 | |
| 385 | b:orderTotal a owl:DatatypeProperty ; |
| 386 | rdfs:label "Order Total" ; |
| 387 | rdfs:domain b:Order ; |
| 388 | rdfs:range xsd:decimal ; |
| 389 | rdfs:comment "Total monetary value of the order. Currency varies (see orderCurrency)." ; |
| 390 | m:mapsToColumn t:order_summary_view.order_total . |
| 391 | |
| 392 | b:orderStatus a owl:DatatypeProperty ; |
| 393 | rdfs:label "Order Status" ; |
| 394 | rdfs:domain b:Order ; |
| 395 | rdfs:range xsd:string ; |
| 396 | rdfs:comment "Current fulfillment status of the order." ; |
| 397 | m:mapsToColumn t:order_summary_view.order_status ; |
| 398 | bv:sampleEnumValues "pending", "confirmed", "shipped", "delivered", "returned", "cancelled" ; |
| 399 | bv:enumValuesFrom t:order_summary_view.order_status . |
| 400 | |
| 401 | b:customerCountry a owl:DatatypeProperty ; |
| 402 | rdfs:label "Customer Country" ; |
| 403 | rdfs:domain b:Order ; |
| 404 | rdfs:range xsd:string ; |
| 405 | rdfs:comment "ISO country code of the ordering customer. NOTE: DENORMALIZED - sourced from customer master data via order_summary_view. Only available for customers who have placed orders. See b:customerCountryMaster for the master data version." ; |
| 406 | rdfs:seeAlso b:customerCountryMaster ; |
| 407 | m:mapsToColumn t:order_summary_view.customer_country ; |
| 408 | bv:sampleEnumValues "DE", "FR", "GB", "US", "NL", "ES" ; |
| 409 | bv:enumValuesFrom t:order_summary_view.customer_country ; |
| 410 | bv:commonEnumType "country" . |
| 411 | |
| 412 | b:productCategory a owl:DatatypeProperty ; |
| 413 | rdfs:label "Product Category" ; |
| 414 | rdfs:domain b:Order ; |
| 415 | rdfs:range xsd:string ; |
| 416 | rdfs:comment "Category of the ordered product. NOTE: DENORMALIZED - sourced from product catalog via order_summary_view. Only available for products that appear in orders. See b:productCategoryMaster for the master data version." ; |
| 417 | rdfs:seeAlso b:productCategoryMaster ; |
| 418 | m:mapsToColumn t:order_summary_view.product_category ; |
| 419 | bv:sampleEnumValues "Electronics", "Clothing", "Home & Garden", "Sports", "Books" ; |
| 420 | bv:enumValuesFrom t:order_summary_view.product_category . |
| 421 | |
| 422 | b:paymentMethod a owl:DatatypeProperty ; |
| 423 | rdfs:label "Payment Method" ; |
| 424 | rdfs:domain b:Order ; |
| 425 | rdfs:range xsd:string ; |
| 426 | rdfs:comment "Method of payment used for the order." ; |
| 427 | m:mapsToColumn t:order_summary_view.payment_method ; |
| 428 | bv:sampleEnumValues "credit_card", "paypal", "bank_transfer", "apple_pay" ; |
| 429 | bv:enumValuesFrom t:order_summary_view.payment_method . |
| 430 | |
| 431 | b:orderCurrency a owl:DatatypeProperty ; |
| 432 | rdfs:label "Order Currency" ; |
| 433 | rdfs:domain b:Order ; |
| 434 | rdfs:range xsd:string ; |
| 435 | rdfs:comment "ISO currency code for the order amount." ; |
| 436 | m:mapsToColumn t:order_summary_view.currency ; |
| 437 | bv:sampleEnumValues "EUR", "GBP" ; |
| 438 | bv:enumValuesFrom t:order_summary_view.currency ; |
| 439 | bv:commonEnumType "currency" . |
| 440 | |
| 441 | b:customerType a owl:DatatypeProperty ; |
| 442 | rdfs:label "Customer Type" ; |
| 443 | rdfs:domain b:Order ; |
| 444 | rdfs:range xsd:string ; |
| 445 | rdfs:comment "Classification of the customer. NOTE: DENORMALIZED - available through order_summary_view. Determines eligibility for reporting (internal/test orders are typically excluded). See b:customerTypeMaster for the master data version." ; |
| 446 | rdfs:seeAlso b:customerTypeMaster ; |
| 447 | m:mapsToColumn t:order_summary_view.customer_type ; |
| 448 | bv:sampleEnumValues "regular", "internal", "wholesale" ; |
| 449 | bv:enumValuesFrom t:order_summary_view.customer_type . |
| 450 | |
| 451 | b:customerId a owl:DatatypeProperty ; |
| 452 | rdfs:label "Customer ID" ; |
| 453 | rdfs:domain b:Order ; |
| 454 | rdfs:range xsd:string ; |
| 455 | rdfs:comment "Customer identifier. NOTE: DENORMALIZED - FK to customers table, available directly in order_summary_view." ; |
| 456 | m:mapsToColumn t:order_summary_view.customer_id . |
| 457 | |
| 458 | b:orderQuantity a owl:DatatypeProperty ; |
| 459 | rdfs:label "Order Quantity" ; |
| 460 | rdfs:domain b:Order ; |
| 461 | rdfs:range xsd:integer ; |
| 462 | rdfs:comment "Number of items in the order." ; |
| 463 | m:mapsToColumn t:order_summary_view.quantity . |
| 464 | |
| 465 | b:isTestOrder a owl:DatatypeProperty ; |
| 466 | rdfs:label "Is Test Order" ; |
| 467 | rdfs:domain b:Order ; |
| 468 | rdfs:range xsd:boolean ; |
| 469 | rdfs:comment "Boolean flag indicating whether this is a test order. Test orders are excluded from revenue and performance metrics." ; |
| 470 | m:mapsToColumn t:order_summary_view.is_test_order ; |
| 471 | bv:commonEnumType "boolean" . |
| 472 | |
| 473 | b:productId a owl:DatatypeProperty ; |
| 474 | rdfs:label "Product ID" ; |
| 475 | rdfs:domain b:Order ; |
| 476 | rdfs:range xsd:string ; |
| 477 | rdfs:comment "Product identifier. NOTE: DENORMALIZED - FK to products table, available directly in order_summary_view." ; |
| 478 | m:mapsToColumn t:order_summary_view.product_id . |
| 479 | |
| 480 | b:productName a owl:DatatypeProperty ; |
| 481 | rdfs:label "Product Name" ; |
| 482 | rdfs:domain b:Product ; |
| 483 | rdfs:range xsd:string ; |
| 484 | rdfs:comment "Display name of the product." ; |
| 485 | m:mapsToColumn t:products.product_name . |
| 486 | |
| 487 | b:productCategoryMaster a owl:DatatypeProperty ; |
| 488 | rdfs:label "Product Category (Master)" ; |
| 489 | rdfs:domain b:Product ; |
| 490 | rdfs:range xsd:string ; |
| 491 | rdfs:comment "Category from the product catalog master table. See also b:productCategory on b:Order for the denormalized version available in order analytics." ; |
| 492 | rdfs:seeAlso b:productCategory ; |
| 493 | m:mapsToColumn t:products.product_category ; |
| 494 | bv:sampleEnumValues "Electronics", "Clothing", "Home & Garden", "Sports", "Books" ; |
| 495 | bv:enumValuesFrom t:products.product_category . |
| 496 | |
| 497 | b:productPrice a owl:DatatypeProperty ; |
| 498 | rdfs:label "Product Price" ; |
| 499 | rdfs:domain b:Product ; |
| 500 | rdfs:range xsd:decimal ; |
| 501 | rdfs:comment "Current list price of the product in EUR." ; |
| 502 | m:mapsToColumn t:products.product_price . |
| 503 | |
| 504 | b:customerSegment a owl:DatatypeProperty ; |
| 505 | rdfs:label "Customer Segment" ; |
| 506 | rdfs:domain b:Customer ; |
| 507 | rdfs:range xsd:string ; |
| 508 | rdfs:comment "Customer segment classification from the customer master table." ; |
| 509 | m:mapsToColumn t:customers.customer_segment ; |
| 510 | bv:sampleEnumValues "Premium", "Standard", "New", "Churned" ; |
| 511 | bv:enumValuesFrom t:customers.customer_segment . |
| 512 | |
| 513 | b:customerName a owl:DatatypeProperty ; |
| 514 | rdfs:label "Customer Name" ; |
| 515 | rdfs:domain b:Customer ; |
| 516 | rdfs:range xsd:string ; |
| 517 | rdfs:comment "Full name of the customer." ; |
| 518 | m:mapsToColumn t:customers.customer_name . |
| 519 | |
| 520 | b:customerEmail a owl:DatatypeProperty ; |
| 521 | rdfs:label "Customer Email" ; |
| 522 | rdfs:domain b:Customer ; |
| 523 | rdfs:range xsd:string ; |
| 524 | rdfs:comment "Primary email address of the customer." ; |
| 525 | m:mapsToColumn t:customers.customer_email . |
| 526 | |
| 527 | b:customerCountryMaster a owl:DatatypeProperty ; |
| 528 | rdfs:label "Customer Country (Master)" ; |
| 529 | rdfs:domain b:Customer ; |
| 530 | rdfs:range xsd:string ; |
| 531 | rdfs:comment "ISO country code from the customer master table. See also b:customerCountry on b:Order for the denormalized version available in order analytics." ; |
| 532 | rdfs:seeAlso b:customerCountry ; |
| 533 | m:mapsToColumn t:customers.customer_country ; |
| 534 | bv:sampleEnumValues "DE", "FR", "GB", "US", "NL", "ES" ; |
| 535 | bv:enumValuesFrom t:customers.customer_country . |
| 536 | |
| 537 | b:customerTypeMaster a owl:DatatypeProperty ; |
| 538 | rdfs:label "Customer Type (Master)" ; |
| 539 | rdfs:domain b:Customer ; |
| 540 | rdfs:range xsd:string ; |
| 541 | rdfs:comment "Customer classification from the master table. See also b:customerType on b:Order for the denormalized version available in order analytics." ; |
| 542 | rdfs:seeAlso b:customerType ; |
| 543 | m:mapsToColumn t:customers.customer_type ; |
| 544 | bv:sampleEnumValues "regular", "internal", "wholesale" ; |
| 545 | bv:enumValuesFrom t:customers.customer_type . |
| 546 | |
| 547 | b:customerCreatedAt a owl:DatatypeProperty ; |
| 548 | rdfs:label "Customer Registration Date" ; |
| 549 | rdfs:domain b:Customer ; |
| 550 | rdfs:range xsd:dateTime ; |
| 551 | rdfs:comment "Timestamp when the customer registered." ; |
| 552 | m:mapsToColumn t:customers.created_at . |
| 553 | |
| 554 | # =========================================================================== |
| 555 | # BUSINESS LAYER - TIME DIMENSIONS |
| 556 | # =========================================================================== |
| 557 | |
| 558 | b:OrderDate a bv:TimeDimension ; |
| 559 | rdfs:label "Order Date" ; |
| 560 | rdfs:comment "Date when the order was placed. Primary time dimension for all order-related metrics." ; |
| 561 | m:mapsToColumn t:order_summary_view.order_date . |
| 562 | |
| 563 | b:CustomerRegistrationDate a bv:TimeDimension ; |
| 564 | rdfs:label "Customer Registration Date" ; |
| 565 | rdfs:comment "Date when the customer registered. Can be used as a time dimension for customer cohort analysis." ; |
| 566 | m:mapsToColumn t:customers.created_at . |
| 567 | |
| 568 | # =========================================================================== |
| 569 | # BUSINESS LAYER - CONSTANTS |
| 570 | # =========================================================================== |
| 571 | |
| 572 | b:gbpToEurExchangeRate a bv:BusinessConstant ; |
| 573 | rdfs:label "GBP to EUR Exchange Rate" ; |
| 574 | rdfs:comment "Fixed exchange rate for converting GBP to EUR. Rate: 1 GBP = 0.85 EUR. To convert GBP amounts to EUR, divide by 0.85. This value is inlined in metric expressions." ; |
| 575 | bv:constantValue "0.85"^^xsd:decimal . |
| 576 | |
| 577 | # =========================================================================== |
| 578 | # BUSINESS LAYER - METRICS (with structured properties) |
| 579 | # =========================================================================== |
| 580 | |
| 581 | b:totalRevenueMetric a bv:Metric ; |
| 582 | rdfs:label "total_revenue" ; |
| 583 | skos:altLabel "Gross Revenue", "Total Sales" ; |
| 584 | rdfs:comment "Total order revenue with automatic GBP to EUR conversion. Includes ALL order types and statuses. For order count see b:orderCountMetric; for average value see b:averageOrderValueMetric." ; |
| 585 | rdfs:seeAlso b:orderCountMetric, b:averageOrderValueMetric ; |
| 586 | bv:metricExpression "SUM(CASE WHEN currency = 'GBP' THEN order_total / {{gbpToEurExchangeRate}} ELSE order_total END)" ; |
| 587 | bv:metricTable t:order_summary_view ; |
| 588 | bv:timeDimension b:OrderDate ; |
| 589 | bv:dependsOnProperty b:orderTotal, b:orderCurrency ; |
| 590 | bv:dependsOnConstant b:gbpToEurExchangeRate ; |
| 591 | bv:metricCategory "Revenue" . |
| 592 | |
| 593 | b:orderCountMetric a bv:Metric ; |
| 594 | rdfs:label "order_count" ; |
| 595 | skos:altLabel "Number of Orders", "Total Orders" ; |
| 596 | rdfs:comment "Total number of orders placed. Counts all orders regardless of status. For revenue see b:totalRevenueMetric." ; |
| 597 | rdfs:seeAlso b:totalRevenueMetric ; |
| 598 | bv:metricExpression "COUNT(*)" ; |
| 599 | bv:metricTable t:order_summary_view ; |
| 600 | bv:timeDimension b:OrderDate ; |
| 601 | bv:dependsOnProperty b:orderId ; |
| 602 | bv:metricCategory "Orders" . |
| 603 | |
| 604 | b:averageOrderValueMetric a bv:Metric ; |
| 605 | rdfs:label "average_order_value" ; |
| 606 | skos:altLabel "AOV", "Avg Order Value" ; |
| 607 | rdfs:comment "Average revenue per order. Equivalent to total_revenue / order_count." ; |
| 608 | rdfs:seeAlso b:totalRevenueMetric, b:orderCountMetric ; |
| 609 | bv:metricExpression "AVG(order_total)" ; |
| 610 | bv:metricTable t:order_summary_view ; |
| 611 | bv:timeDimension b:OrderDate ; |
| 612 | bv:dependsOnProperty b:orderTotal ; |
| 613 | bv:metricCategory "Revenue" . |
| 614 | |
| 615 | b:returnRateMetric a bv:Metric ; |
| 616 | rdfs:label "return_rate" ; |
| 617 | skos:altLabel "Return %", "Refund Rate" ; |
| 618 | rdfs:comment "Percentage of orders that were returned or refunded, excluding test orders and internal staff purchases. Formula: returned_orders / total_orders * 100. A value of 5% means one in twenty orders was returned." ; |
| 619 | bv:metricExpression """100.0 * SUM(CASE WHEN order_status = 'returned' THEN 1 ELSE 0 END) |
| 620 | / NULLIF(COUNT(*), 0)""" ; |
| 621 | bv:metricTable t:order_summary_view ; |
| 622 | bv:metricPreFilter "customer_type <> 'internal' AND is_test_order = false" ; |
| 623 | bv:timeDimension b:OrderDate ; |
| 624 | bv:dependsOnProperty b:orderStatus, b:customerType, b:isTestOrder ; |
| 625 | bv:metricCategory "Orders" . |
| 626 | |
| 627 | b:uniqueCustomersMetric a bv:Metric ; |
| 628 | rdfs:label "unique_customers" ; |
| 629 | skos:altLabel "Distinct Customers", "Active Buyers" ; |
| 630 | rdfs:comment "Number of distinct customers who placed orders in the period. NOTE: This is an ACTIVITY-BASED count - only customers with at least one order are counted. This is NOT a master data count of all registered customers." ; |
| 631 | bv:metricExpression "COUNT(DISTINCT customer_id)" ; |
| 632 | bv:metricTable t:order_summary_view ; |
| 633 | bv:timeDimension b:OrderDate ; |
| 634 | bv:dependsOnProperty b:customerId ; |
| 635 | bv:metricCategory "Customers" . |
| 636 | |
| 637 | b:totalItemsSoldMetric a bv:Metric ; |
| 638 | rdfs:label "total_items_sold" ; |
| 639 | skos:altLabel "Units Sold", "Total Quantity" ; |
| 640 | rdfs:comment "Total number of items sold across all orders." ; |
| 641 | bv:metricExpression "SUM(quantity)" ; |
| 642 | bv:metricTable t:order_summary_view ; |
| 643 | bv:timeDimension b:OrderDate ; |
| 644 | bv:dependsOnProperty b:orderQuantity ; |
| 645 | bv:metricCategory "Orders" . |
| 646 | |
| 647 | # Multi-table metric using SQL template escape hatch |
| 648 | b:revenuePerCustomerSegmentMetric a bv:Metric ; |
| 649 | rdfs:label "revenue_per_customer_segment" ; |
| 650 | rdfs:comment "Average revenue per customer, broken down by customer segment. Requires joining orders with customer master data. For total revenue without segmentation, see b:totalRevenueMetric." ; |
| 651 | rdfs:seeAlso b:totalRevenueMetric ; |
| 652 | bv:metricSql """ |
| 653 | SELECT DATE_TRUNC('{{granularity}}', o.order_date) AS time_dimension |
| 654 | {{select_dimensions}}, |
| 655 | CASE WHEN COUNT(DISTINCT c.customer_id) > 0 |
| 656 | THEN SUM(o.order_total) / COUNT(DISTINCT c.customer_id) |
| 657 | ELSE 0 END AS metric_value |
| 658 | FROM order_summary_view o |
| 659 | INNER JOIN customers c ON o.customer_id = c.customer_id |
| 660 | WHERE o.order_date >= '{{start_date}}' AND o.order_date < '{{end_date}}' |
| 661 | {{where_filters}} |
| 662 | GROUP BY 1 {{group_by_dimensions}} |
| 663 | ORDER BY 1 |
| 664 | """ ; |
| 665 | bv:timeDimension b:OrderDate ; |
| 666 | bv:dependsOnProperty b:orderTotal, b:customerId, b:customerSegment ; |
| 667 | bv:dependsOnRelationship b:customerHasOrder ; |
| 668 | bv:metricCategory "Revenue" . |
| 669 | |
| 670 | b:newCustomerRegistrationsMetric a bv:Metric ; |
| 671 | rdfs:label "new_customer_registrations" ; |
| 672 | skos:altLabel "New Signups", "Customer Registrations" ; |
| 673 | rdfs:comment "Number of new customer registrations per period. Excludes internal (staff) customers. For activity-based customer counts (customers who placed orders), see b:uniqueCustomersMetric." ; |
| 674 | rdfs:seeAlso b:uniqueCustomersMetric ; |
| 675 | bv:metricExpression "COUNT(*)" ; |
| 676 | bv:metricTable t:customers ; |
| 677 | bv:metricPreFilter "customer_type <> 'internal'" ; |
| 678 | bv:timeDimension b:CustomerRegistrationDate ; |
| 679 | bv:dependsOnProperty b:customerTypeMaster ; |
| 680 | bv:metricCategory "Customers" . |
| 681 |
Connect your data, define metrics, and start asking questions in plain English.
Get Started Free