/// OPENSEARCH TUTORIAL: Comprehensive Query Examples for Bakery Management System /// This tutorial covers: Basic CRUD, Search, Aggregations, Multi-search, and Percolator queries /// Use Elasticsearch VSCode extension for easy execution /// Get Elasticsearch version information GET / /// =================================================== /// STEP 1: INDEX SETUP AND DATA PREPARATION /// =================================================== /// Delete the index if it exists (cleanup for fresh start) DELETE /bakery-items /// Create the index with proper field mappings /// - keyword: exact match fields (item names, categories) /// - float: numeric values (prices) /// - date: timestamp fields /// - boolean: true/false flags /// - nested: complex objects with sub-properties PUT /bakery-items { "mappings": { "properties": { "item": { "type": "keyword" // Exact match for item names }, "category": { "type": "keyword" // Exact match for categories (cakes, bread) }, "price": { "type": "float" // Numeric field for price calculations }, "baked_date": { "type": "date" // Date field for temporal queries }, "product_type": { "type": "keyword" // Sale or rent classification }, "is_bulk_discount": { "type": "boolean" // Boolean flag for discount eligibility }, "ingrediants": { "type": "nested", // Nested type for complex ingredient objects "properties": { "name": { "type": "keyword" // Exact match for ingredient names } } } } } } /// Sample Data Ingestion - Creating diverse test data /// =================================================== /// Insert chocolate cake (regular price, no discount) POST /bakery-items/_doc { "item": "Chocolate Cake", "category": "cakes", "price": 15, "baked_date": "2023-07-01T00:00:00Z", "product_type": "sale", "is_bulk_discount": false, "ingrediants": [ { "name": "chocolate" }, { "name": "flour" } ] } /// Insert chocolate cake (higher price, with bulk discount) POST /bakery-items/_doc { "item": "Chocolate Cake", "category": "cakes", "price": 18, "baked_date": "2023-07-04T00:00:00Z", "product_type": "sale", "is_bulk_discount": true, "ingrediants": [ { "name": "chocolate" }, { "name": "flour" } ] } /// Insert vanilla cake (rental item, lower price) POST /bakery-items/_doc { "item": "Vanilla Cake", "category": "cakes", "price": 12, "baked_date": "2023-07-02T00:00:00Z", "product_type": "rent", "is_bulk_discount": false, "ingrediants": [ { "name": "vanilla" }, { "name": "flour" } ] } /// Insert croissant (sale item with unusual ingredients) POST /bakery-items/_doc { "item": "Croissant", "category": "cakes", "price": 5, "baked_date": "2023-07-03T00:00:00Z" , "product_type": "sale", "is_bulk_discount": true, "ingrediants": [ { "name": "sauce" }, { "name": "vinegar" } ] } /// Insert sourdough bread (bread category, no discount) POST /bakery-items/_doc { "item": "Sourdough Bread", "category": "bread", "price": 8, "baked_date": "2023-07-05T00:00:00Z", "product_type": "sale", "is_bulk_discount": false, "ingrediants": [ { "name": "flour" }, { "name": "yeast" } ] } /// Insert whole wheat bread (bread category, with bulk discount) POST /bakery-items/_doc { "item": "Whole Wheat Bread", "category": "bread", "price": 6, "baked_date": "2023-07-07T00:00:00Z", "product_type": "sale", "is_bulk_discount": true, "ingrediants": [ { "name": "whole wheat flour" }, { "name": "water" } ] } /// Insert baguette (rental bread item) POST /bakery-items/_doc { "item": "Baguette", "category": "bread", "price": 3, "baked_date": "2023-07-06T00:00:00Z", "product_type": "rent", "is_bulk_discount": false, "ingrediants": [ { "name": "flour" }, { "name": "water" } ] } /// =================================================== /// =================================================== /// STEP 2: BASIC SEARCH QUERIES /// =================================================== /// Basic search: Find all items in "cakes" category, sorted by price /// Uses match query for text matching and sort for ordering results GET /bakery-items/_search { "query": { "match": { "category": "cakes" } }, "sort": ["price"] } /// =================================================== /// STEP 3: ADVANCED SEARCH WITH COLLAPSE /// =================================================== /// Collapse results by category: Show one representative item per category /// Useful for creating category overview pages GET /bakery-items/_search { "query": { "match_all": {} // Match all documents in the index }, "collapse": { "field": "category", // Group results by category field "inner_hits": { "name": "category_hits", // Name for the grouped results "size": 2 // Show top 2 items per category } }, "sort": ["price"] // Primary sort by price (determines which item represents each category) } /// FAILED EXAMPLE: Collapse by nested field (doesn't work as expected) /// Demonstrates common mistake - collapse doesn't work directly with nested fields GET /bakery-items/_search { "query": { "match": { "category": "cakes" } }, "inner_hits": { "ingrediants": { "name": "ingredient_hits", "collapse": { "field": "ingrediants.name" // This approach doesn't work for nested fields } } }, "sort": ["price"] } /// =================================================== /// STEP 4: AGGREGATIONS - NESTED FIELD ANALYSIS /// =================================================== /// Get unique ingredients in cakes category using nested aggregation /// Demonstrates how to work with nested objects in aggregations GET /bakery-items/_search { "size": 0, "query": { "match": { "category": "cakes" } }, "aggs": { "unique_ingredients": { "nested": { "path": "ingrediants" }, "aggs": { "ingredient_names": { "terms": { "field": "ingrediants.name", "size": 10 } } } } } } /// =================================================== /// STEP 5: CATEGORY-BASED AGGREGATIONS WITH TOP HITS /// =================================================== /// Group all items by category and show actual documents for each category /// Useful for creating detailed category pages with sample items GET /bakery-items/_search { "size": 0, // Don't return top-level hits "aggs": { "by_category": { "terms": { "field": "category", // Create buckets for each category "size": 10 // Support up to 10 categories }, "aggs": { "category_docs": { "top_hits": { "size": 100 // Return up to 100 documents per category } } } } } } /// =================================================== /// STEP 6: COMPLEX NESTED AGGREGATION WITH REVERSE NESTED /// =================================================== /// Advanced: Aggregate by ingredient names and show parent documents /// Demonstrates nested → reverse_nested pattern for complex analysis GET /bakery-items/_search { "query": { // "match_all": {} // Match all documents "match": { "category": "cakes" } }, "size": 0, // No Top Level hits needed "aggs": { "ingredients_stats": { "nested": { "path": "ingrediants" }, "aggs": { "ingredient_names": { "terms": { "field": "ingrediants.name", "size": 10 }, "aggs": { "back_to_parent": { "reverse_nested": {}, "aggs": { "parent_docs": { "top_hits": { "size": 100 } } } } } } } } } } /// =================================================== /// STEP 7: MULTI-LEVEL AGGREGATIONS WITH FILTERS /// =================================================== /// Complex aggregation: Group by product_type, then apply multiple filters /// Demonstrates filters aggregation for creating detailed business reports GET /bakery-items/_search { "size": 0, // Only aggregation results needed "aggs": { "product_type_buckets": { "terms": { "field": "product_type", // First level: group by sale/rent "size": 10 }, "aggs": { "sale_or_discount": { "filters": { // Second level: apply multiple filter criteria "filters": { "is_bulk_discount": { "term": { "is_bulk_discount": true // Filter 1: Items with bulk discount } }, "sale": { "bool": { "must": [ { "term": { "product_type": "sale" } }, // Filter 2: Sale items { "term": { "is_bulk_discount": false } } // without bulk discount ] } }, "rent": { "term": { "product_type": "rent" // Filter 3: Rental items } } } }, "aggs": { "top_items": { "top_hits": { "size": 5 // Show top 5 items in each filter bucket } } } } } } } } /// =================================================== /// STEP 8: MULTI-SEARCH API (BATCH QUERIES) /// =================================================== /// Execute multiple searches in a single request for better performance /// Each pair of lines represents: 1) search parameters, 2) query body /// (Note: This won't work in Elasticsearch VSCode extension, but you can't get it working in curl) GET /_msearch { "index": "bakery-items"} { "query": { "term": { "is_bulk_discount": true } }, "size": 5, "_source": ["item", "category", "price", "product_type", "is_bulk_discount"] } { "index": "bakery-items"} { "query": { "bool": { "must": [ { "term": { "product_type": "sale" } }, { "term": { "is_bulk_discount": false } } ] } }, "size": 5, "_source": ["item", "category", "price", "product_type", "is_bulk_discount"] } { "index": "bakery-items"} { "query": { "term": { "product_type": "rent" } }, "size": 5, "_source": ["item", "category", "price", "product_type", "is_bulk_discount"] } /// =================================================== /// STEP 9: PERCOLATOR QUERIES (REVERSE SEARCH) /// =================================================== /// Reverse search setup: Instead of "find documents matching a query" /// Percolator enables "find queries matching a document" /// Use case: Customer alerts, recommendation engines, real-time matching /// Delete any existing percolator index DELETE /bakery-alerts /// Create percolator index with special "percolator" field type /// Must include mappings for all fields that will be used in stored queries PUT /bakery-alerts { "mappings": { "properties": { "query": { "type": "percolator" // Special field type for storing queries }, "category": { "type": "keyword" // Must match source index mapping }, "price": { "type": "float" // Must match source index mapping }, "is_bulk_discount": { "type": "boolean" // Must match source index mapping } } } } /// Store Customer 1's preference as a percolator query /// "Alert me when cakes under $15 are available" PUT /bakery-alerts/_doc/cake_under_15 { "query": { "bool": { "must": [ { "term": { "category": "cakes" } }, { "range": { "price": { "lt": 15 } } } ] } } } /// Store Customer 2's preference as a percolator query /// "Alert me when bread items have bulk discounts" PUT /bakery-alerts/_doc/bread_bulk_discount { "query": { "bool": { "must": [ { "term": { "category": "bread" } }, { "term": { "is_bulk_discount": true } } ] } } } /// Test the percolator: Check which customer alerts match a new product /// This query asks: "Which stored customer preferences match this vanilla cake?" GET /bakery-alerts/_search { "query": { "percolate": { "field": "query", // Use the percolator field "document": { // Test document against stored queries "item": "Vanilla Cake", "category": "cakes", "price": 12, // Price: $12 (matches cake_under_15 alert) "baked_date": "2023-07-02T00:00:00Z", "product_type": "rent", "is_bulk_discount": false, "ingrediants": [ { "name": "vanilla" }, { "name": "flour" } ] } } } }