Skip to content

Instantly share code, notes, and snippets.

@Swoorup
Created May 29, 2025 01:50
Show Gist options
  • Save Swoorup/a8d6dfe7d36f825a72b2c45dda91b4ac to your computer and use it in GitHub Desktop.
Save Swoorup/a8d6dfe7d36f825a72b2c45dda91b4ac to your computer and use it in GitHub Desktop.
Playground to test elasticsearch
/// 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" } ]
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment