Build powerful search experiences with Elasticsearch
# Elasticsearch Search Optimization
Master full-text search with Elasticsearch using Google Antigravity IDE. This guide covers index design, query optimization, and relevance tuning.
## Why Elasticsearch?
Elasticsearch provides distributed search with powerful analytics. Google Antigravity IDE's Gemini 3 engine suggests optimal mappings and query patterns.
## Index Mapping
```json
// PUT /products
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2,
"analysis": {
"analyzer": {
"product_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase", "asciifolding", "product_synonyms", "product_stemmer"]
},
"autocomplete_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase", "asciifolding", "autocomplete_filter"]
}
},
"filter": {
"product_synonyms": {
"type": "synonym",
"synonyms_path": "analysis/synonyms.txt"
},
"product_stemmer": {
"type": "stemmer",
"language": "english"
},
"autocomplete_filter": {
"type": "edge_ngram",
"min_gram": 2,
"max_gram": 20
}
}
}
},
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "product_analyzer",
"fields": {
"keyword": { "type": "keyword" },
"autocomplete": {
"type": "text",
"analyzer": "autocomplete_analyzer",
"search_analyzer": "standard"
}
}
},
"description": {
"type": "text",
"analyzer": "product_analyzer"
},
"category": {
"type": "keyword"
},
"brand": {
"type": "keyword"
},
"price": {
"type": "scaled_float",
"scaling_factor": 100
},
"rating": {
"type": "float"
},
"in_stock": {
"type": "boolean"
},
"tags": {
"type": "keyword"
},
"created_at": {
"type": "date"
},
"popularity_score": {
"type": "rank_feature"
}
}
}
}
```
## Search Query
```typescript
// lib/elasticsearch.ts
import { Client } from "@elastic/elasticsearch";
const client = new Client({ node: process.env.ELASTICSEARCH_URL });
interface SearchParams {
query: string;
category?: string;
minPrice?: number;
maxPrice?: number;
inStock?: boolean;
sortBy?: "relevance" | "price_asc" | "price_desc" | "rating";
page?: number;
limit?: number;
}
export async function searchProducts(params: SearchParams) {
const { query, category, minPrice, maxPrice, inStock, sortBy = "relevance", page = 1, limit = 20 } = params;
const must: object[] = [];
const filter: object[] = [];
// Full-text search with boosting
if (query) {
must.push({
multi_match: {
query,
fields: ["name^3", "name.autocomplete^2", "description", "brand^2", "tags"],
type: "best_fields",
fuzziness: "AUTO",
prefix_length: 2
}
});
}
// Filters
if (category) {
filter.push({ term: { category } });
}
if (minPrice !== undefined || maxPrice !== undefined) {
filter.push({
range: {
price: {
...(minPrice !== undefined && { gte: minPrice }),
...(maxPrice !== undefined && { lte: maxPrice })
}
}
});
}
if (inStock !== undefined) {
filter.push({ term: { in_stock: inStock } });
}
// Build sort
const sort: object[] = [];
switch (sortBy) {
case "price_asc":
sort.push({ price: "asc" });
break;
case "price_desc":
sort.push({ price: "desc" });
break;
case "rating":
sort.push({ rating: "desc" });
break;
default:
sort.push({ _score: "desc" });
}
const response = await client.search({
index: "products",
body: {
query: {
bool: {
must: must.length > 0 ? must : [{ match_all: {} }],
filter
}
},
sort,
from: (page - 1) * limit,
size: limit,
aggs: {
categories: { terms: { field: "category", size: 20 } },
brands: { terms: { field: "brand", size: 20 } },
price_ranges: {
range: {
field: "price",
ranges: [
{ to: 50 },
{ from: 50, to: 100 },
{ from: 100, to: 200 },
{ from: 200 }
]
}
},
avg_rating: { avg: { field: "rating" } }
},
highlight: {
fields: {
name: {},
description: { fragment_size: 150, number_of_fragments: 3 }
},
pre_tags: ["<mark>"],
post_tags: ["</mark>"]
}
}
});
return {
hits: response.hits.hits.map(hit => ({
id: hit._id,
score: hit._score,
...hit._source,
highlights: hit.highlight
})),
total: response.hits.total.value,
aggregations: response.aggregations
};
}
```
## Autocomplete
```typescript
export async function autocomplete(prefix: string, limit = 10) {
const response = await client.search({
index: "products",
body: {
query: {
bool: {
should: [
{
match: {
"name.autocomplete": {
query: prefix,
operator: "and"
}
}
},
{
match_phrase_prefix: {
name: {
query: prefix,
boost: 2
}
}
}
]
}
},
size: limit,
_source: ["name", "category", "brand"]
}
});
return response.hits.hits.map(hit => hit._source);
}
```
## Best Practices
- Design mappings before indexing data
- Use appropriate analyzers for your use case
- Apply filters for structured data queries
- Implement aggregations for faceted search
- Use highlighting for search results
- Monitor cluster health and performance
Google Antigravity IDE provides Elasticsearch patterns and automatically suggests optimal query structures for your search applications.This Elasticsearch prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their elasticsearch implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For Elasticsearch projects, consider mentioning your framework version, coding style, and any specific libraries you're using.