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#>t:order_summary_view
m:Table
t:customers
m:Table
t:products
m:Table
t:service_items
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
t:service_items.service_id
m:Column
t:service_items.service_name
m:Column
t:service_items.service_category
m:Column
t:service_items.service_price
m:Column
t:order_summary_view.service_id
m:Column
b:Order
owl:Class
b:Customer
owl:Class
b:Purchasable
owl:Class
b:Product
owl:Class
b:ServiceItem
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:orderHasPurchasable
owl:ObjectProperty
b:orderHasServiceItem
owl:ObjectProperty
b:serviceItemInOrder
owl:ObjectProperty
b:orderId
owl:DatatypeProperty
b:orderDate
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:serviceId
owl:DatatypeProperty
b:serviceName
owl:DatatypeProperty
b:serviceCategory
owl:DatatypeProperty
b:servicePrice
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: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
b:newRegistrations_correlates_returnRate
bv:MetricCorrelation
b:returnRate_drives_averageOrderValue
bv:MetricCorrelation
| 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/sourceEntity) for single-table queries and metricSql for multi-table joins." . |
| 24 | |
| 25 | # =========================================================================== |
| 26 | # TECHNICAL LAYER - TABLES |
| 27 | # =========================================================================== |
| 28 | |
| 29 | t:order_summary_view a m:Table ; |
| 30 | rdfs:label "Order Summary View" ; |
| 31 | rdfs:comment "Denormalized view joining orders, customers, and products. Primary fact table for order analytics." . |
| 32 | |
| 33 | t:customers a m:Table ; |
| 34 | rdfs:label "Customers" ; |
| 35 | rdfs:comment "Customer master data including segmentation and demographics." . |
| 36 | |
| 37 | t:products a m:Table ; |
| 38 | rdfs:label "Products" ; |
| 39 | rdfs:comment "Product catalog with categories and pricing." . |
| 40 | |
| 41 | t:service_items a m:Table ; |
| 42 | rdfs:label "Service Items" ; |
| 43 | rdfs:comment "Service offerings such as warranties, installations, and subscriptions." . |
| 44 | |
| 45 | # =========================================================================== |
| 46 | # TECHNICAL LAYER - COLUMNS |
| 47 | # =========================================================================== |
| 48 | |
| 49 | t:order_summary_view.order_id a m:Column ; |
| 50 | rdfs:label "Order ID" ; |
| 51 | rdfs:comment "Unique order identifier (PK)." ; |
| 52 | m:belongsToTable t:order_summary_view . |
| 53 | |
| 54 | t:order_summary_view.order_date a m:Column ; |
| 55 | rdfs:label "Order Date" ; |
| 56 | rdfs:comment "Date the order was placed. Used as the primary time dimension for order metrics." ; |
| 57 | m:belongsToTable t:order_summary_view . |
| 58 | |
| 59 | t:order_summary_view.order_total a m:Column ; |
| 60 | rdfs:label "Order Total" ; |
| 61 | rdfs:comment "Total order amount. Currency is indicated by the currency column; may be EUR or GBP." ; |
| 62 | m:belongsToTable t:order_summary_view . |
| 63 | |
| 64 | t:order_summary_view.order_status a m:Column ; |
| 65 | rdfs:label "Order Status" ; |
| 66 | rdfs:comment "Current order fulfillment status: pending, confirmed, shipped, delivered, returned, cancelled." ; |
| 67 | m:belongsToTable t:order_summary_view . |
| 68 | |
| 69 | t:order_summary_view.customer_country a m:Column ; |
| 70 | rdfs:label "Customer Country" ; |
| 71 | rdfs:comment "ISO country code of the ordering customer. Denormalized from customer master." ; |
| 72 | m:belongsToTable t:order_summary_view . |
| 73 | |
| 74 | t:order_summary_view.product_category a m:Column ; |
| 75 | rdfs:label "Product Category" ; |
| 76 | rdfs:comment "Category of the ordered product. Denormalized from product catalog." ; |
| 77 | m:belongsToTable t:order_summary_view . |
| 78 | |
| 79 | t:order_summary_view.payment_method a m:Column ; |
| 80 | rdfs:label "Payment Method" ; |
| 81 | rdfs:comment "Payment method used for the order: credit_card, paypal, bank_transfer, apple_pay." ; |
| 82 | m:belongsToTable t:order_summary_view . |
| 83 | |
| 84 | t:order_summary_view.currency a m:Column ; |
| 85 | rdfs:label "Currency" ; |
| 86 | rdfs:comment "ISO currency code for the order amount (EUR, GBP)." ; |
| 87 | m:belongsToTable t:order_summary_view . |
| 88 | |
| 89 | t:order_summary_view.customer_type a m:Column ; |
| 90 | rdfs:label "Customer Type" ; |
| 91 | rdfs:comment "Customer classification: regular, internal (staff), wholesale." ; |
| 92 | m:belongsToTable t:order_summary_view . |
| 93 | |
| 94 | t:order_summary_view.is_test_order a m:Column ; |
| 95 | rdfs:label "Is Test Order" ; |
| 96 | rdfs:comment "Boolean flag indicating whether this is a test order that should be excluded from reporting." ; |
| 97 | m:belongsToTable t:order_summary_view . |
| 98 | |
| 99 | t:order_summary_view.customer_id a m:Column ; |
| 100 | rdfs:label "Customer ID" ; |
| 101 | rdfs:comment "FK to customers table. Denormalized into the view for join-free access." ; |
| 102 | m:belongsToTable t:order_summary_view . |
| 103 | |
| 104 | t:order_summary_view.quantity a m:Column ; |
| 105 | rdfs:label "Quantity" ; |
| 106 | rdfs:comment "Number of items in the order line." ; |
| 107 | m:belongsToTable t:order_summary_view . |
| 108 | |
| 109 | t:order_summary_view.product_id a m:Column ; |
| 110 | rdfs:label "Product ID" ; |
| 111 | rdfs:comment "FK to products table. Identifies the product in the order." ; |
| 112 | m:belongsToTable t:order_summary_view . |
| 113 | |
| 114 | t:customers.customer_id a m:Column ; |
| 115 | rdfs:label "Customer ID" ; |
| 116 | rdfs:comment "Customer unique identifier (PK)." ; |
| 117 | m:belongsToTable t:customers . |
| 118 | |
| 119 | t:customers.customer_segment a m:Column ; |
| 120 | rdfs:label "Customer Segment" ; |
| 121 | rdfs:comment "Customer segment classification: Premium, Standard, New, Churned." ; |
| 122 | m:belongsToTable t:customers . |
| 123 | |
| 124 | t:customers.customer_name a m:Column ; |
| 125 | rdfs:label "Customer Name" ; |
| 126 | rdfs:comment "Full name of the customer." ; |
| 127 | m:belongsToTable t:customers . |
| 128 | |
| 129 | t:customers.customer_email a m:Column ; |
| 130 | rdfs:label "Customer Email" ; |
| 131 | rdfs:comment "Primary email address of the customer." ; |
| 132 | m:belongsToTable t:customers . |
| 133 | |
| 134 | t:customers.customer_country a m:Column ; |
| 135 | rdfs:label "Customer Country" ; |
| 136 | rdfs:comment "ISO country code of the customer. Master data source for the denormalized order_summary_view.customer_country." ; |
| 137 | m:belongsToTable t:customers . |
| 138 | |
| 139 | t:customers.customer_type a m:Column ; |
| 140 | rdfs:label "Customer Type" ; |
| 141 | rdfs:comment "Customer classification: regular, internal (staff), wholesale. Master data source for the denormalized order_summary_view.customer_type." ; |
| 142 | m:belongsToTable t:customers . |
| 143 | |
| 144 | t:customers.created_at a m:Column ; |
| 145 | rdfs:label "Created At" ; |
| 146 | rdfs:comment "Timestamp when the customer record was created (registration date)." ; |
| 147 | m:belongsToTable t:customers . |
| 148 | |
| 149 | t:products.product_id a m:Column ; |
| 150 | rdfs:label "Product ID" ; |
| 151 | rdfs:comment "Product unique identifier (PK)." ; |
| 152 | m:belongsToTable t:products . |
| 153 | |
| 154 | t:products.product_name a m:Column ; |
| 155 | rdfs:label "Product Name" ; |
| 156 | rdfs:comment "Display name of the product." ; |
| 157 | m:belongsToTable t:products . |
| 158 | |
| 159 | t:products.product_category a m:Column ; |
| 160 | rdfs:label "Product Category" ; |
| 161 | rdfs:comment "Category the product belongs to: Electronics, Clothing, Home & Garden, Sports, Books." ; |
| 162 | m:belongsToTable t:products . |
| 163 | |
| 164 | t:products.product_price a m:Column ; |
| 165 | rdfs:label "Product Price" ; |
| 166 | rdfs:comment "Current list price of the product in EUR." ; |
| 167 | m:belongsToTable t:products . |
| 168 | |
| 169 | # --- service_items columns --- |
| 170 | |
| 171 | t:service_items.service_id a m:Column ; |
| 172 | rdfs:label "Service ID" ; |
| 173 | rdfs:comment "Unique service item identifier (PK)." ; |
| 174 | m:belongsToTable t:service_items . |
| 175 | |
| 176 | t:service_items.service_name a m:Column ; |
| 177 | rdfs:label "Service Name" ; |
| 178 | rdfs:comment "Display name of the service item." ; |
| 179 | m:belongsToTable t:service_items . |
| 180 | |
| 181 | t:service_items.service_category a m:Column ; |
| 182 | rdfs:label "Service Category" ; |
| 183 | rdfs:comment "Category the service belongs to: Warranty, Installation, Subscription, Support." ; |
| 184 | m:belongsToTable t:service_items . |
| 185 | |
| 186 | t:service_items.service_price a m:Column ; |
| 187 | rdfs:label "Service Price" ; |
| 188 | rdfs:comment "Current price of the service item in EUR." ; |
| 189 | m:belongsToTable t:service_items . |
| 190 | |
| 191 | t:order_summary_view.service_id a m:Column ; |
| 192 | rdfs:label "Service ID" ; |
| 193 | rdfs:comment "FK to service_items table. Identifies the service in the order. Null when the order line is for a product." ; |
| 194 | m:belongsToTable t:order_summary_view . |
| 195 | |
| 196 | # =========================================================================== |
| 197 | # BUSINESS LAYER - CLASSES |
| 198 | # =========================================================================== |
| 199 | |
| 200 | b:Order a owl:Class ; |
| 201 | rdfs:label "Order" ; |
| 202 | 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." ; |
| 203 | rdfs:seeAlso "ttl-uri"><https://schema.org/Order> ; |
| 204 | skos:example "ORD-2025-001234, ORD-2025-005678" ; |
| 205 | m:mapsToTable t:order_summary_view . |
| 206 | |
| 207 | b:Customer a owl:Class ; |
| 208 | rdfs:label "Customer" ; |
| 209 | skos:altLabel "Buyer", "Account" ; |
| 210 | rdfs:comment "A registered customer of Acme Shop." ; |
| 211 | rdfs:seeAlso "ttl-uri"><https://schema.org/Person> ; |
| 212 | skos:example "Jane Smith, Acme Corporation" ; |
| 213 | m:mapsToTable t:customers . |
| 214 | |
| 215 | # --- Polymorphic relationship: Purchasable (Product or ServiceItem) --- |
| 216 | # An Order can reference either a Product or a ServiceItem via the common |
| 217 | # superclass Purchasable. This models a polymorphic association in OWL: |
| 218 | # orderHasPurchasable has range b:Purchasable, and both Product and ServiceItem |
| 219 | # are subclasses, so the relationship accepts either type. |
| 220 | |
| 221 | b:Purchasable a owl:Class ; |
| 222 | rdfs:label "Purchasable" ; |
| 223 | rdfs:comment "Abstract superclass for anything that can appear as a line item in an order. Subclassed by Product (physical goods) and ServiceItem (services, warranties, subscriptions). This class has no direct table mapping — use the concrete subclasses Product (t:products) or ServiceItem (t:service_items) for queries." . |
| 224 | |
| 225 | b:Product a owl:Class ; |
| 226 | rdfs:subClassOf b:Purchasable ; |
| 227 | rdfs:label "Product" ; |
| 228 | skos:altLabel "Item", "SKU" ; |
| 229 | rdfs:comment "A physical product available in the Acme Shop catalog." ; |
| 230 | rdfs:seeAlso "ttl-uri"><https://schema.org/Product> ; |
| 231 | skos:example "Wireless Mouse Pro, Organic Cotton T-Shirt, Standing Desk" ; |
| 232 | owl:disjointWith b:ServiceItem ; |
| 233 | m:mapsToTable t:products . |
| 234 | |
| 235 | b:ServiceItem a owl:Class ; |
| 236 | rdfs:subClassOf b:Purchasable ; |
| 237 | rdfs:label "Service Item" ; |
| 238 | skos:altLabel "Service", "Add-on" ; |
| 239 | rdfs:comment "A service offering such as a warranty, installation, or subscription that can be purchased alongside or independently of a product." ; |
| 240 | rdfs:seeAlso "ttl-uri"><https://schema.org/Service> ; |
| 241 | skos:example "2-Year Extended Warranty, Professional Installation, Monthly Support Plan" ; |
| 242 | owl:disjointWith b:Product ; |
| 243 | m:mapsToTable t:service_items . |
| 244 | |
| 245 | # --- Subclasses with filters --- |
| 246 | |
| 247 | b:WholesaleCustomer a owl:Class, m:BusinessView ; |
| 248 | rdfs:subClassOf b:Customer ; |
| 249 | rdfs:label "Wholesale Customer" ; |
| 250 | rdfs:comment "Customer purchasing in bulk at wholesale prices. Identified by customer_type = 'wholesale' in the order view." ; |
| 251 | m:mapsToTable t:order_summary_view ; |
| 252 | m:joinCondition "order_summary_view.customer_type = 'wholesale'"^^xsd:string . |
| 253 | |
| 254 | b:InternalCustomer a owl:Class, m:BusinessView ; |
| 255 | rdfs:subClassOf b:Customer ; |
| 256 | rdfs:label "Internal Customer" ; |
| 257 | rdfs:comment "Internal staff purchases. Typically excluded from revenue reporting. Identified by customer_type = 'internal'." ; |
| 258 | m:mapsToTable t:order_summary_view ; |
| 259 | m:joinCondition "order_summary_view.customer_type = 'internal'"^^xsd:string . |
| 260 | |
| 261 | b:PremiumWholesaleCustomer a owl:Class, m:BusinessView ; |
| 262 | rdfs:subClassOf b:WholesaleCustomer ; |
| 263 | rdfs:label "Premium Wholesale Customer" ; |
| 264 | rdfs:comment "High-value wholesale customers with premium pricing agreements. Identified by customer_type = 'wholesale' AND customer_segment = 'Premium'." ; |
| 265 | m:mapsToTable t:order_summary_view ; |
| 266 | m:joinCondition "order_summary_view.customer_type = 'wholesale' AND customers.customer_segment = 'Premium'"^^xsd:string . |
| 267 | |
| 268 | b:WholesaleCustomer owl:disjointWith b:InternalCustomer . |
| 269 | |
| 270 | b:ReturnedOrder a owl:Class, m:BusinessView ; |
| 271 | rdfs:subClassOf b:Order ; |
| 272 | rdfs:label "Returned Order" ; |
| 273 | rdfs:comment "Orders that were returned or refunded by the customer." ; |
| 274 | m:mapsToTable t:order_summary_view ; |
| 275 | m:joinCondition "order_summary_view.order_status = 'returned'"^^xsd:string . |
| 276 | |
| 277 | b:CancelledOrder a owl:Class, m:BusinessView ; |
| 278 | rdfs:subClassOf b:Order ; |
| 279 | rdfs:label "Cancelled Order" ; |
| 280 | rdfs:comment "Orders that were cancelled before fulfillment. NOTE: Mutually exclusive with ReturnedOrder - an order is either cancelled or returned, not both." ; |
| 281 | rdfs:seeAlso b:ReturnedOrder ; |
| 282 | m:mapsToTable t:order_summary_view ; |
| 283 | m:joinCondition "order_summary_view.order_status = 'cancelled'"^^xsd:string . |
| 284 | |
| 285 | b:ReturnedOrder owl:disjointWith b:CancelledOrder . |
| 286 | |
| 287 | # =========================================================================== |
| 288 | # BUSINESS LAYER - RELATIONSHIPS |
| 289 | # =========================================================================== |
| 290 | |
| 291 | b:customerHasOrder a owl:ObjectProperty ; |
| 292 | rdfs:domain b:Customer ; |
| 293 | rdfs:range b:Order ; |
| 294 | rdfs:label "customer has order" ; |
| 295 | rdfs:comment "Links a customer to all orders they have placed. Joined via customer_id." ; |
| 296 | owl:inverseOf b:orderForCustomer ; |
| 297 | m:realizedBy "customers.customer_id = order_summary_view.customer_id"^^xsd:string . |
| 298 | |
| 299 | b:orderForCustomer a owl:ObjectProperty ; |
| 300 | rdfs:domain b:Order ; |
| 301 | rdfs:range b:Customer ; |
| 302 | rdfs:label "order for customer" ; |
| 303 | rdfs:comment "Links an order back to the customer who placed it. Inverse of customerHasOrder." ; |
| 304 | owl:inverseOf b:customerHasOrder ; |
| 305 | m:realizedBy "order_summary_view.customer_id = customers.customer_id"^^xsd:string . |
| 306 | |
| 307 | b:orderHasProduct a owl:ObjectProperty ; |
| 308 | rdfs:subPropertyOf b:orderHasPurchasable ; |
| 309 | rdfs:domain b:Order ; |
| 310 | rdfs:range b:Product ; |
| 311 | rdfs:label "order has product" ; |
| 312 | rdfs:comment "Links an order to the physical product purchased. Joined via product_id." ; |
| 313 | owl:inverseOf b:productInOrder ; |
| 314 | m:realizedBy "order_summary_view.product_id = products.product_id"^^xsd:string . |
| 315 | |
| 316 | b:productInOrder a owl:ObjectProperty ; |
| 317 | rdfs:domain b:Product ; |
| 318 | rdfs:range b:Order ; |
| 319 | rdfs:label "product in order" ; |
| 320 | rdfs:comment "Links a product to all orders in which it appears. Inverse of orderHasProduct." ; |
| 321 | owl:inverseOf b:orderHasProduct ; |
| 322 | m:realizedBy "products.product_id = order_summary_view.product_id"^^xsd:string . |
| 323 | |
| 324 | # --- Polymorphic purchasable relationship --- |
| 325 | # orderHasPurchasable accepts any Purchasable subclass (Product or ServiceItem). |
| 326 | # The specific subtype relationships (orderHasProduct, orderHasServiceItem) are |
| 327 | # declared as sub-properties, so navigating orderHasPurchasable returns both. |
| 328 | |
| 329 | b:orderHasPurchasable a owl:ObjectProperty ; |
| 330 | rdfs:domain b:Order ; |
| 331 | rdfs:range b:Purchasable ; |
| 332 | rdfs:label "order has purchasable" ; |
| 333 | rdfs:comment "Links an order to any purchasable item (product or service). This is the polymorphic relationship — use orderHasProduct or orderHasServiceItem for type-specific access. Realized via product_id or service_id depending on the subtype." ; |
| 334 | m:realizedBy "order_summary_view.product_id = products.product_id OR order_summary_view.service_id = service_items.service_id"^^xsd:string . |
| 335 | |
| 336 | b:orderHasServiceItem a owl:ObjectProperty ; |
| 337 | rdfs:subPropertyOf b:orderHasPurchasable ; |
| 338 | rdfs:domain b:Order ; |
| 339 | rdfs:range b:ServiceItem ; |
| 340 | rdfs:label "order has service item" ; |
| 341 | rdfs:comment "Links an order to the service item purchased. Joined via service_id." ; |
| 342 | owl:inverseOf b:serviceItemInOrder ; |
| 343 | m:realizedBy "order_summary_view.service_id = service_items.service_id"^^xsd:string . |
| 344 | |
| 345 | b:serviceItemInOrder a owl:ObjectProperty ; |
| 346 | rdfs:domain b:ServiceItem ; |
| 347 | rdfs:range b:Order ; |
| 348 | rdfs:label "service item in order" ; |
| 349 | rdfs:comment "Links a service item to all orders in which it appears. Inverse of orderHasServiceItem." ; |
| 350 | owl:inverseOf b:orderHasServiceItem ; |
| 351 | m:realizedBy "service_items.service_id = order_summary_view.service_id"^^xsd:string . |
| 352 | |
| 353 | # =========================================================================== |
| 354 | # BUSINESS LAYER - PROPERTIES (Dimensions) |
| 355 | # =========================================================================== |
| 356 | |
| 357 | b:orderId a owl:DatatypeProperty ; |
| 358 | rdfs:label "Order ID" ; |
| 359 | rdfs:domain b:Order ; |
| 360 | rdfs:range xsd:string ; |
| 361 | rdfs:comment "Unique order identifier." ; |
| 362 | m:mapsToColumn t:order_summary_view.order_id . |
| 363 | |
| 364 | b:orderDate a owl:DatatypeProperty ; |
| 365 | rdfs:label "Order Date" ; |
| 366 | rdfs:domain b:Order ; |
| 367 | rdfs:range xsd:date ; |
| 368 | rdfs:comment "Date when the order was placed. Primary time dimension for all order-related metrics." ; |
| 369 | m:mapsToColumn t:order_summary_view.order_date . |
| 370 | |
| 371 | b:orderTotal a owl:DatatypeProperty ; |
| 372 | rdfs:label "Order Total" ; |
| 373 | rdfs:domain b:Order ; |
| 374 | rdfs:range xsd:decimal ; |
| 375 | rdfs:comment "Total monetary value of the order. Currency varies (see orderCurrency)." ; |
| 376 | m:mapsToColumn t:order_summary_view.order_total . |
| 377 | |
| 378 | b:orderStatus a owl:DatatypeProperty ; |
| 379 | rdfs:label "Order Status" ; |
| 380 | rdfs:domain b:Order ; |
| 381 | rdfs:range xsd:string ; |
| 382 | rdfs:comment "Current fulfillment status of the order." ; |
| 383 | m:mapsToColumn t:order_summary_view.order_status ; |
| 384 | bv:sampleEnumValues "pending", "confirmed", "shipped", "delivered", "returned", "cancelled" ; |
| 385 | bv:enumType "dynamic" . |
| 386 | |
| 387 | b:customerCountry a owl:DatatypeProperty ; |
| 388 | rdfs:label "Customer Country" ; |
| 389 | rdfs:domain b:Order ; |
| 390 | rdfs:range xsd:string ; |
| 391 | rdfs:comment "ISO country code of the ordering customer. Only available for customers who have placed orders. See b:customerCountryMaster for the master data version." ; |
| 392 | bv:masterProperty b:customerCountryMaster ; |
| 393 | rdfs:seeAlso b:customerCountryMaster ; |
| 394 | m:mapsToColumn t:order_summary_view.customer_country ; |
| 395 | bv:sampleEnumValues "DE", "FR", "GB", "US", "NL", "ES" ; |
| 396 | bv:enumType "country" . |
| 397 | |
| 398 | b:productCategory a owl:DatatypeProperty ; |
| 399 | rdfs:label "Product Category" ; |
| 400 | rdfs:domain b:Order ; |
| 401 | rdfs:range xsd:string ; |
| 402 | rdfs:comment "Category of the ordered product. Only available for products that appear in orders. See b:productCategoryMaster for the master data version." ; |
| 403 | bv:masterProperty b:productCategoryMaster ; |
| 404 | rdfs:seeAlso b:productCategoryMaster ; |
| 405 | m:mapsToColumn t:order_summary_view.product_category ; |
| 406 | bv:sampleEnumValues "Electronics", "Clothing", "Home & Garden", "Sports", "Books" ; |
| 407 | bv:enumType "dynamic" . |
| 408 | |
| 409 | b:paymentMethod a owl:DatatypeProperty ; |
| 410 | rdfs:label "Payment Method" ; |
| 411 | rdfs:domain b:Order ; |
| 412 | rdfs:range xsd:string ; |
| 413 | rdfs:comment "Method of payment used for the order." ; |
| 414 | m:mapsToColumn t:order_summary_view.payment_method ; |
| 415 | bv:sampleEnumValues "credit_card", "paypal", "bank_transfer", "apple_pay" ; |
| 416 | bv:enumType "dynamic" . |
| 417 | |
| 418 | b:orderCurrency a owl:DatatypeProperty ; |
| 419 | rdfs:label "Order Currency" ; |
| 420 | rdfs:domain b:Order ; |
| 421 | rdfs:range xsd:string ; |
| 422 | rdfs:comment "ISO currency code for the order amount." ; |
| 423 | m:mapsToColumn t:order_summary_view.currency ; |
| 424 | bv:sampleEnumValues "EUR", "GBP" ; |
| 425 | bv:enumType "currency" . |
| 426 | |
| 427 | b:customerType a owl:DatatypeProperty ; |
| 428 | rdfs:label "Customer Type" ; |
| 429 | rdfs:domain b:Order ; |
| 430 | rdfs:range xsd:string ; |
| 431 | rdfs:comment "Classification of the customer. Determines eligibility for reporting (internal/test orders are typically excluded). See b:customerTypeMaster for the master data version." ; |
| 432 | bv:masterProperty b:customerTypeMaster ; |
| 433 | rdfs:seeAlso b:customerTypeMaster ; |
| 434 | m:mapsToColumn t:order_summary_view.customer_type ; |
| 435 | bv:sampleEnumValues "regular", "internal", "wholesale" ; |
| 436 | bv:enumType "dynamic" . |
| 437 | |
| 438 | b:customerId a owl:DatatypeProperty ; |
| 439 | rdfs:label "Customer ID" ; |
| 440 | rdfs:domain b:Order ; |
| 441 | rdfs:range xsd:string ; |
| 442 | rdfs:comment "Customer identifier. FK to customers table, available directly in order_summary_view." ; |
| 443 | m:mapsToColumn t:order_summary_view.customer_id . |
| 444 | |
| 445 | b:orderQuantity a owl:DatatypeProperty ; |
| 446 | rdfs:label "Order Quantity" ; |
| 447 | rdfs:domain b:Order ; |
| 448 | rdfs:range xsd:integer ; |
| 449 | rdfs:comment "Number of items in the order." ; |
| 450 | m:mapsToColumn t:order_summary_view.quantity . |
| 451 | |
| 452 | b:isTestOrder a owl:DatatypeProperty ; |
| 453 | rdfs:label "Is Test Order" ; |
| 454 | rdfs:domain b:Order ; |
| 455 | rdfs:range xsd:boolean ; |
| 456 | rdfs:comment "Boolean flag indicating whether this is a test order. Test orders are excluded from revenue and performance metrics." ; |
| 457 | m:mapsToColumn t:order_summary_view.is_test_order ; |
| 458 | bv:enumType "boolean" . |
| 459 | |
| 460 | b:productId a owl:DatatypeProperty ; |
| 461 | rdfs:label "Product ID" ; |
| 462 | rdfs:domain b:Order ; |
| 463 | rdfs:range xsd:string ; |
| 464 | rdfs:comment "Product identifier. FK to products table, available directly in order_summary_view." ; |
| 465 | m:mapsToColumn t:order_summary_view.product_id . |
| 466 | |
| 467 | b:productName a owl:DatatypeProperty ; |
| 468 | rdfs:label "Product Name" ; |
| 469 | rdfs:domain b:Product ; |
| 470 | rdfs:range xsd:string ; |
| 471 | rdfs:comment "Display name of the product." ; |
| 472 | m:mapsToColumn t:products.product_name . |
| 473 | |
| 474 | b:productCategoryMaster a owl:DatatypeProperty ; |
| 475 | rdfs:label "Product Category (Master)" ; |
| 476 | rdfs:domain b:Product ; |
| 477 | rdfs:range xsd:string ; |
| 478 | rdfs:comment "Category from the product catalog master table. See also b:productCategory on b:Order for the denormalized version available in order analytics." ; |
| 479 | rdfs:seeAlso b:productCategory ; |
| 480 | m:mapsToColumn t:products.product_category ; |
| 481 | bv:sampleEnumValues "Electronics", "Clothing", "Home & Garden", "Sports", "Books" ; |
| 482 | bv:enumType "dynamic" . |
| 483 | |
| 484 | b:productPrice a owl:DatatypeProperty ; |
| 485 | rdfs:label "Product Price" ; |
| 486 | rdfs:domain b:Product ; |
| 487 | rdfs:range xsd:decimal ; |
| 488 | rdfs:comment "Current list price of the product in EUR." ; |
| 489 | m:mapsToColumn t:products.product_price . |
| 490 | |
| 491 | # --- ServiceItem properties --- |
| 492 | |
| 493 | b:serviceId a owl:DatatypeProperty ; |
| 494 | rdfs:label "Service ID" ; |
| 495 | rdfs:domain b:ServiceItem ; |
| 496 | rdfs:range xsd:string ; |
| 497 | rdfs:comment "Unique service item identifier." ; |
| 498 | m:mapsToColumn t:service_items.service_id . |
| 499 | |
| 500 | b:serviceName a owl:DatatypeProperty ; |
| 501 | rdfs:label "Service Name" ; |
| 502 | rdfs:domain b:ServiceItem ; |
| 503 | rdfs:range xsd:string ; |
| 504 | rdfs:comment "Display name of the service item." ; |
| 505 | m:mapsToColumn t:service_items.service_name . |
| 506 | |
| 507 | b:serviceCategory a owl:DatatypeProperty ; |
| 508 | rdfs:label "Service Category" ; |
| 509 | rdfs:domain b:ServiceItem ; |
| 510 | rdfs:range xsd:string ; |
| 511 | rdfs:comment "Category of the service item." ; |
| 512 | m:mapsToColumn t:service_items.service_category ; |
| 513 | bv:sampleEnumValues "Warranty", "Installation", "Subscription", "Support" ; |
| 514 | bv:enumType "dynamic" . |
| 515 | |
| 516 | b:servicePrice a owl:DatatypeProperty ; |
| 517 | rdfs:label "Service Price" ; |
| 518 | rdfs:domain b:ServiceItem ; |
| 519 | rdfs:range xsd:decimal ; |
| 520 | rdfs:comment "Current price of the service item in EUR." ; |
| 521 | m:mapsToColumn t:service_items.service_price . |
| 522 | |
| 523 | b:customerSegment a owl:DatatypeProperty ; |
| 524 | rdfs:label "Customer Segment" ; |
| 525 | rdfs:domain b:Customer ; |
| 526 | rdfs:range xsd:string ; |
| 527 | rdfs:comment "Customer segment classification from the customer master table." ; |
| 528 | m:mapsToColumn t:customers.customer_segment ; |
| 529 | bv:sampleEnumValues "Premium", "Standard", "New", "Churned" ; |
| 530 | bv:enumType "dynamic" . |
| 531 | |
| 532 | b:customerName a owl:DatatypeProperty ; |
| 533 | rdfs:label "Customer Name" ; |
| 534 | rdfs:domain b:Customer ; |
| 535 | rdfs:range xsd:string ; |
| 536 | rdfs:comment "Full name of the customer." ; |
| 537 | m:mapsToColumn t:customers.customer_name . |
| 538 | |
| 539 | b:customerEmail a owl:DatatypeProperty ; |
| 540 | rdfs:label "Customer Email" ; |
| 541 | rdfs:domain b:Customer ; |
| 542 | rdfs:range xsd:string ; |
| 543 | rdfs:comment "Primary email address of the customer. Contains PII — access is restricted." ; |
| 544 | bv:sensitivityLevel "Confidential" ; |
| 545 | bv:complianceCategory "PII" ; |
| 546 | bv:maskingRule "redact" ; |
| 547 | m:mapsToColumn t:customers.customer_email . |
| 548 | |
| 549 | b:customerCountryMaster a owl:DatatypeProperty ; |
| 550 | rdfs:label "Customer Country (Master)" ; |
| 551 | rdfs:domain b:Customer ; |
| 552 | rdfs:range xsd:string ; |
| 553 | 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." ; |
| 554 | rdfs:seeAlso b:customerCountry ; |
| 555 | m:mapsToColumn t:customers.customer_country ; |
| 556 | bv:sampleEnumValues "DE", "FR", "GB", "US", "NL", "ES" ; |
| 557 | bv:enumType "dynamic" . |
| 558 | |
| 559 | b:customerTypeMaster a owl:DatatypeProperty ; |
| 560 | rdfs:label "Customer Type (Master)" ; |
| 561 | rdfs:domain b:Customer ; |
| 562 | rdfs:range xsd:string ; |
| 563 | rdfs:comment "Customer classification from the master table. See also b:customerType on b:Order for the denormalized version available in order analytics." ; |
| 564 | rdfs:seeAlso b:customerType ; |
| 565 | m:mapsToColumn t:customers.customer_type ; |
| 566 | bv:sampleEnumValues "regular", "internal", "wholesale" ; |
| 567 | bv:enumType "dynamic" . |
| 568 | |
| 569 | b:customerCreatedAt a owl:DatatypeProperty ; |
| 570 | rdfs:label "Customer Registration Date" ; |
| 571 | rdfs:domain b:Customer ; |
| 572 | rdfs:range xsd:dateTime ; |
| 573 | rdfs:comment "Timestamp when the customer registered." ; |
| 574 | m:mapsToColumn t:customers.created_at . |
| 575 | |
| 576 | # =========================================================================== |
| 577 | # BUSINESS LAYER - CONSTANTS |
| 578 | # =========================================================================== |
| 579 | |
| 580 | b:gbpToEurExchangeRate a bv:BusinessConstant ; |
| 581 | rdfs:label "GBP to EUR Exchange Rate" ; |
| 582 | 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." ; |
| 583 | bv:constantValue "0.85"^^xsd:decimal . |
| 584 | |
| 585 | # =========================================================================== |
| 586 | # BUSINESS LAYER - METRICS (with structured properties) |
| 587 | # =========================================================================== |
| 588 | |
| 589 | b:totalRevenueMetric a bv:Metric ; |
| 590 | rdfs:label "Total Revenue" ; |
| 591 | skos:altLabel "Gross Revenue", "Total Sales" ; |
| 592 | 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." ; |
| 593 | rdfs:seeAlso b:orderCountMetric, b:averageOrderValueMetric ; |
| 594 | bv:metricExpression "SUM(CASE WHEN b:orderCurrency = 'GBP' THEN b:orderTotal / {{gbpToEurExchangeRate}} ELSE b:orderTotal END)" ; |
| 595 | bv:sourceEntity b:Order ; |
| 596 | bv:timeDimension b:orderDate ; |
| 597 | bv:dependsOnProperty b:orderTotal, b:orderCurrency ; |
| 598 | bv:dependsOnConstant b:gbpToEurExchangeRate ; |
| 599 | bv:metricCategory "Revenue" . |
| 600 | |
| 601 | b:orderCountMetric a bv:Metric ; |
| 602 | rdfs:label "Order Count" ; |
| 603 | skos:altLabel "Number of Orders", "Total Orders" ; |
| 604 | rdfs:comment "Total number of orders placed. Counts all orders regardless of status. For revenue see b:totalRevenueMetric." ; |
| 605 | rdfs:seeAlso b:totalRevenueMetric ; |
| 606 | bv:metricExpression "COUNT(*)" ; |
| 607 | bv:sourceEntity b:Order ; |
| 608 | bv:timeDimension b:orderDate ; |
| 609 | bv:dependsOnProperty b:orderId ; |
| 610 | bv:metricCategory "Orders" . |
| 611 | |
| 612 | b:averageOrderValueMetric a bv:Metric ; |
| 613 | rdfs:label "Average Order Value" ; |
| 614 | skos:altLabel "AOV", "Avg Order Value" ; |
| 615 | rdfs:comment "Average revenue per order. Equivalent to total_revenue / order_count." ; |
| 616 | rdfs:seeAlso b:totalRevenueMetric, b:orderCountMetric ; |
| 617 | bv:metricExpression "AVG(b:orderTotal)" ; |
| 618 | bv:sourceEntity b:Order ; |
| 619 | bv:timeDimension b:orderDate ; |
| 620 | bv:dependsOnProperty b:orderTotal ; |
| 621 | bv:metricCategory "Revenue" . |
| 622 | |
| 623 | b:returnRateMetric a bv:Metric ; |
| 624 | rdfs:label "Return Rate" ; |
| 625 | skos:altLabel "Return %", "Refund Rate" ; |
| 626 | 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." ; |
| 627 | bv:metricExpression """100.0 * SUM(CASE WHEN b:orderStatus = 'returned' THEN 1 ELSE 0 END) |
| 628 | / NULLIF(COUNT(*), 0)""" ; |
| 629 | bv:sourceEntity b:Order ; |
| 630 | bv:metricPreFilter "b:customerType <> 'internal' AND b:isTestOrder = false" ; |
| 631 | bv:timeDimension b:orderDate ; |
| 632 | bv:dependsOnProperty b:orderStatus, b:customerType, b:isTestOrder ; |
| 633 | bv:metricCategory "Orders" . |
| 634 | |
| 635 | b:uniqueCustomersMetric a bv:Metric ; |
| 636 | rdfs:label "Unique Customers" ; |
| 637 | skos:altLabel "Distinct Customers", "Active Buyers" ; |
| 638 | 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." ; |
| 639 | bv:metricExpression "COUNT(DISTINCT b:customerId)" ; |
| 640 | bv:sourceEntity b:Order ; |
| 641 | bv:timeDimension b:orderDate ; |
| 642 | bv:dependsOnProperty b:customerId ; |
| 643 | bv:metricCategory "Customers" . |
| 644 | |
| 645 | b:totalItemsSoldMetric a bv:Metric ; |
| 646 | rdfs:label "Total Items Sold" ; |
| 647 | skos:altLabel "Units Sold", "Total Quantity" ; |
| 648 | rdfs:comment "Total number of items sold across all orders." ; |
| 649 | bv:metricExpression "SUM(b:orderQuantity)" ; |
| 650 | bv:sourceEntity b:Order ; |
| 651 | bv:timeDimension b:orderDate ; |
| 652 | bv:dependsOnProperty b:orderQuantity ; |
| 653 | bv:metricCategory "Orders" . |
| 654 | |
| 655 | # Multi-table metric using SQL template escape hatch |
| 656 | b:revenuePerCustomerSegmentMetric a bv:Metric ; |
| 657 | rdfs:label "Revenue Per Customer Segment" ; |
| 658 | 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." ; |
| 659 | rdfs:seeAlso b:totalRevenueMetric ; |
| 660 | bv:metricSql """ |
| 661 | SELECT DATE_TRUNC('{{granularity}}', order_summary_view.order_date) AS time_dimension |
| 662 | {{select_dimensions}}, |
| 663 | CASE WHEN COUNT(DISTINCT customers.customer_id) > 0 |
| 664 | THEN SUM(order_summary_view.order_total) / COUNT(DISTINCT customers.customer_id) |
| 665 | ELSE 0 END AS metric_value |
| 666 | FROM order_summary_view |
| 667 | INNER JOIN customers ON order_summary_view.customer_id = customers.customer_id |
| 668 | WHERE order_summary_view.order_date >= '{{start_date}}' AND order_summary_view.order_date < '{{end_date}}' |
| 669 | {{where_filters}} |
| 670 | GROUP BY 1 {{group_by_dimensions}} |
| 671 | ORDER BY 1 |
| 672 | """ ; |
| 673 | bv:timeDimension b:orderDate ; |
| 674 | bv:dependsOnProperty b:orderTotal, b:customerId, b:customerSegment ; |
| 675 | bv:dependsOnRelationship b:customerHasOrder ; |
| 676 | bv:metricCategory "Revenue" . |
| 677 | |
| 678 | b:newCustomerRegistrationsMetric a bv:Metric ; |
| 679 | rdfs:label "New Customer Registrations" ; |
| 680 | skos:altLabel "New Signups", "Customer Registrations" ; |
| 681 | 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." ; |
| 682 | rdfs:seeAlso b:uniqueCustomersMetric ; |
| 683 | bv:metricExpression "COUNT(*)" ; |
| 684 | bv:sourceEntity b:Customer ; |
| 685 | bv:metricPreFilter "b:customerTypeMaster <> 'internal'" ; |
| 686 | bv:timeDimension b:customerCreatedAt ; |
| 687 | bv:dependsOnProperty b:customerTypeMaster ; |
| 688 | bv:metricCategory "Customers" . |
| 689 | |
| 690 | # ================================================================ |
| 691 | # CORRELATIONS — How metrics relate to each other |
| 692 | # ================================================================ |
| 693 | |
| 694 | # Statistical: new customer registrations correlate with return rate |
| 695 | b:newRegistrations_correlates_returnRate a bv:MetricCorrelation ; |
| 696 | rdfs:label "New Registrations ↔ Return Rate" ; |
| 697 | rdfs:comment "New customers return items at higher rates than repeat buyers — unfamiliar with sizing and product quality. The effect flattens at high registration volumes." ; |
| 698 | bv:sourceMetric b:newCustomerRegistrationsMetric ; |
| 699 | bv:targetMetric b:returnRateMetric ; |
| 700 | bv:correlationType "statistical" ; |
| 701 | bv:correlationStrength "0.62" ; |
| 702 | bv:correlationCurve "logarithmic" . |
| 703 | |
| 704 | # Causal: high return rates drive down average order value |
| 705 | b:returnRate_drives_averageOrderValue a bv:MetricCorrelation ; |
| 706 | rdfs:label "Return Rate → AOV" ; |
| 707 | rdfs:comment "Higher return rates tend to reduce effective AOV as returned items deflate averages." ; |
| 708 | bv:sourceMetric b:returnRateMetric ; |
| 709 | bv:targetMetric b:averageOrderValueMetric ; |
| 710 | bv:correlationType "causal" ; |
| 711 | bv:correlationStrength "moderate" ; |
| 712 | bv:correlationCurve "inverse" . |
| 713 |
Connect your data, define metrics, and start asking questions in plain English.
Get Started Free