# Quick Start Tutorial
Let's build a simple blog search engine in 5 minutes:
## Step 1: Define Your Schema
```elixir
alias TantivyEx.{Index, Schema}
# Create a new schema
schema = Schema.new()
# Add fields for a blog post
schema = Schema.add_text_field(schema, "title", :text_stored)
schema = Schema.add_text_field(schema, "content", :text)
schema = Schema.add_text_field(schema, "author", :text_stored)
schema = Schema.add_text_field(schema, "tags", :text)
schema = Schema.add_u64_field(schema, "published_at", :fast_stored)
schema = Schema.add_f64_field(schema, "rating", :fast_stored)
schema = Schema.add_facet_field(schema, "category", :facet)
```
## Step 2: Create Your Index
```elixir
# Option 1: Create a new persistent index
index_path = "/tmp/blog_search_index"
{:ok, index} = Index.create_in_dir(index_path, schema)
# Option 2: Open existing index or create if it doesn't exist (recommended)
{:ok, index} = Index.open_or_create(index_path, schema)
# Option 3: Open an existing index
{:ok, index} = Index.open(index_path)
# Option 4: Create an in-memory index for testing
{:ok, index} = Index.create_in_ram(schema)
```
### Index Persistence
The `open_or_create/2` function is recommended for most applications as it:
- Creates a new index if the directory doesn't exist
- Opens an existing index if it's already present
- Handles directory creation automatically
- Provides seamless index persistence across application restarts
```elixir
# This will work whether the index exists or not
{:ok, index} = Index.open_or_create("/var/lib/myapp/search_index", schema)
```
## Step 3: Add Documents
```elixir
# Sample blog posts
blog_posts = [
%{
"title" => "Getting Started with Elixir",
"content" => "Elixir is a dynamic, functional language designed for building maintainable applications...",
"author" => "Jane Doe",
"tags" => "elixir functional programming beginner",
"published_at" => 1640995200,
"rating" => 4.5,
"category" => "/programming/elixir"
},
%{
"title" => "Advanced Phoenix Patterns",
"content" => "Phoenix provides powerful abstractions for building real-time web applications...",
"author" => "John Smith",
"tags" => "phoenix web elixir advanced",
"published_at" => 1641081600,
"rating" => 4.8,
"category" => "/programming/phoenix"
},
%{
"title" => "Rust Performance Tips",
"content" => "Rust offers zero-cost abstractions and memory safety without garbage collection...",
"author" => "Alice Johnson",
"tags" => "rust performance systems",
"published_at" => 1641168000,
"rating" => 4.2,
"category" => "/programming/rust"
}
]
# Add documents to the index
{:ok, writer} = TantivyEx.IndexWriter.new(index)
Enum.each(blog_posts, fn post ->
:ok = TantivyEx.IndexWriter.add_document(writer, post)
end)
# Commit changes
:ok = TantivyEx.IndexWriter.commit(writer)
```
## Step 4: Search Your Content
```elixir
# Simple text search
{:ok, searcher} = TantivyEx.Searcher.new(index)
{:ok, results} = TantivyEx.Searcher.search(searcher, "elixir", 10)
IO.inspect(results, label: "Elixir posts")
# Search in specific fields
{:ok, results} = TantivyEx.Searcher.search(searcher, "title:phoenix", 10)
IO.inspect(results, label: "Phoenix in title")
# Boolean queries
{:ok, results} = TantivyEx.Searcher.search(searcher, "elixir AND phoenix", 10)
IO.inspect(results, label: "Elixir AND Phoenix")
# Range queries
{:ok, results} = TantivyEx.Searcher.search(searcher, "rating:[4.0 TO *]", 10)
IO.inspect(results, label: "High-rated posts")
# Facet queries
{:ok, results} = TantivyEx.Searcher.search(searcher, "category:\"/programming/elixir\"", 10)
IO.inspect(results, label: "Elixir category")
```
## Step 5: Handle Results
```elixir
defmodule BlogSearch do
alias TantivyEx.Index
def search_posts(index, query, limit \\ 10) do
{:ok, searcher} = TantivyEx.Searcher.new(index)
case TantivyEx.Searcher.search(searcher, query, limit) do
{:ok, results} ->
formatted_results = Enum.map(results, &format_result/1)
{:ok, formatted_results}
{:error, reason} ->
{:error, "Search failed: #{inspect(reason)}"}
end
end
defp format_result(doc) do
%{
title: Map.get(doc, "title"),
author: Map.get(doc, "author"),
rating: Map.get(doc, "rating"),
published_at: Map.get(doc, "published_at") |> format_timestamp(),
snippet: Map.get(doc, "content") |> create_snippet(100)
}
end
defp format_timestamp(timestamp) when is_integer(timestamp) do
DateTime.from_unix!(timestamp) |> DateTime.to_string()
end
defp format_timestamp(_), do: "Unknown"
defp create_snippet(content, max_length) when is_binary(content) do
if String.length(content) <= max_length do
content
else
content
|> String.slice(0, max_length)
|> String.trim_trailing()
|> Kernel.<>("...")
end
end
defp create_snippet(_, _), do: ""
end
# Use the search module
{:ok, formatted_results} = BlogSearch.search_posts(index, "elixir programming")
IO.inspect(formatted_results)
```
## Next Steps
Congratulations! You now have a working full-text search engine. Here's what you can explore next:
- **[Core Concepts](core-concepts.md)** - Understand the fundamental building blocks
- **[Schema Design Guide](schema.md)** - Learn advanced schema design patterns
- **[Search Guide](search.md)** - Master advanced query techniques
- **[Performance Tuning](performance-tuning.md)** - Optimize for production workloads
- **[Production Deployment](production-deployment.md)** - Deploy in production environments
## Common Next Steps
### Adding More Fields
Extend your schema with additional field types:
```elixir
# Add more field types
{:ok, schema} = Schema.add_bytes_field(schema, "thumbnail", :stored)
{:ok, schema} = Schema.add_bool_field(schema, "is_published", :fast_stored)
{:ok, schema} = Schema.add_date_field(schema, "created_at", :fast_stored)
```
### Real-time Updates
Learn how to update documents in real-time:
```elixir
# Update an existing document
{:ok, writer} = TantivyEx.IndexWriter.new(index)
updated_doc = %{"title" => "Updated Elixir Guide", "content" => "..."}
:ok = TantivyEx.IndexWriter.update_document(writer, "title:\"Getting Started with Elixir\"", updated_doc)
:ok = TantivyEx.IndexWriter.commit(writer)
```
### Advanced Searching
Explore complex queries and filters:
```elixir
# Complex boolean queries
{:ok, results} = TantivyEx.Searcher.search(searcher, "(elixir OR phoenix) AND rating:[4.0 TO *]", 10)
# Faceted search using Query module
{:ok, parser} = TantivyEx.Query.parser(index, ["category", "author"])
{:ok, query} = TantivyEx.Query.parse(parser, "programming")
{:ok, results} = TantivyEx.Searcher.search(searcher, query, 10)
```