Use Cases

This section provides recommended configurations and examples for common use cases.

Enable customers to search products by name, description, or other attributes.

public class Product
{
    private long id;
    private String name;
    private String description;
    private String category;
    private String brand;
    private double price;
    private int stock;
    // ...
}

public class ProductDocumentPopulator extends DocumentPopulator<Product>
{
    @Override
    public void populate(Document document, Product product)
    {
        // Full-text searchable fields
        document.add(createTextField("name", product.getName()));
        document.add(createTextField("description", product.getDescription()));
        document.add(createTextField("brand", product.getBrand()));

        // Exact match fields for filtering
        document.add(createStringField("category", product.getCategory()));

        // Numeric fields for range queries
        document.add(createDoubleField("price", product.getPrice()));
        document.add(createIntField("stock", product.getStock()));
    }
}
// Setup
LuceneContext<Product> context = LuceneContext.New(
    Paths.get("/data/product-index"),
    new ProductDocumentPopulator()
);

GigaMap<Product> products = GigaMap.New();
LuceneIndex<Product> searchIndex = products.index().register(LuceneIndex.Category(context));

// Search by keyword
List<Product> results = searchIndex.query("name:wireless");

// Search across multiple fields
List<Product> results = searchIndex.query("name:bluetooth OR description:bluetooth");

// Filter by category
List<Product> electronics = searchIndex.query("category:Electronics");

// Price range
Query priceQuery = DoublePoint.newRangeQuery("price", 50.0, 200.0);
List<Product> midRange = searchIndex.query(priceQuery);

// In-stock items only
Query stockQuery = IntPoint.newRangeQuery("stock", 1, Integer.MAX_VALUE);
List<Product> available = searchIndex.query(stockQuery);

Full-text search for articles, blog posts, or documentation.

public class Article
{
    private long id;
    private String title;
    private String content;
    private String author;
    private String[] tags;
    private LocalDate publishedDate;
    // ...
}

public class ArticleDocumentPopulator extends DocumentPopulator<Article>
{
    @Override
    public void populate(Document document, Article article)
    {
        document.add(createTextField("title", article.getTitle()));
        document.add(createTextField("content", article.getContent()));
        document.add(createStringField("author", article.getAuthor()));

        // Index tags as searchable text
        if (article.getTags() != null)
        {
            for (String tag : article.getTags())
            {
                document.add(createStringField("tag", tag));
            }
        }

        // Store date as long for range queries
        if (article.getPublishedDate() != null)
        {
            document.add(createLongField("publishedDate",
                article.getPublishedDate().toEpochDay()));
        }
    }
}
// Search in title
List<Article> results = searchIndex.query("title:\"machine learning\"");

// Search in content
List<Article> results = searchIndex.query("content:tutorial");

// Search by author
List<Article> byAuthor = searchIndex.query("author:Jane");

// Search by tag
List<Article> tagged = searchIndex.query("tag:python");

// Recent articles (last 30 days)
long thirtyDaysAgo = LocalDate.now().minusDays(30).toEpochDay();
Query recentQuery = LongPoint.newRangeQuery("publishedDate", thirtyDaysAgo, Long.MAX_VALUE);
List<Article> recent = searchIndex.query(recentQuery);

Search customers by name, email, or other identifying information.

public class Customer
{
    private long id;
    private String firstName;
    private String lastName;
    private String email;
    private String phone;
    private String city;
    private String country;
    // ...
}

public class CustomerDocumentPopulator extends DocumentPopulator<Customer>
{
    @Override
    public void populate(Document document, Customer customer)
    {
        // Full-text searchable for partial matching
        document.add(createTextField("firstName", customer.getFirstName()));
        document.add(createTextField("lastName", customer.getLastName()));
        document.add(createTextField("fullName",
            customer.getFirstName() + " " + customer.getLastName()));

        // Exact match for email lookups
        document.add(createStringField("email", customer.getEmail().toLowerCase()));

        // Searchable location
        document.add(createTextField("city", customer.getCity()));
        document.add(createStringField("country", customer.getCountry()));
    }
}
// Search by name (partial match)
List<Customer> results = searchIndex.query("fullName:John*");

// Exact email lookup
List<Customer> byEmail = searchIndex.query("email:john.doe@example.com");

// Search by city
List<Customer> berliners = searchIndex.query("city:Berlin");

// Filter by country
List<Customer> german = searchIndex.query("country:DE");

Search support tickets and knowledge base articles.

public class SupportTicket
{
    private long id;
    private String subject;
    private String description;
    private String status;
    private String priority;
    private String assignee;
    private LocalDateTime createdAt;
    // ...
}

public class TicketDocumentPopulator extends DocumentPopulator<SupportTicket>
{
    @Override
    public void populate(Document document, SupportTicket ticket)
    {
        document.add(createTextField("subject", ticket.getSubject()));
        document.add(createTextField("description", ticket.getDescription()));
        document.add(createStringField("status", ticket.getStatus()));
        document.add(createStringField("priority", ticket.getPriority()));
        document.add(createStringField("assignee", ticket.getAssignee()));
        document.add(createLongField("createdAt",
            ticket.getCreatedAt().toEpochSecond(ZoneOffset.UTC)));
    }
}
// Search by keyword
List<SupportTicket> results = searchIndex.query("subject:login OR description:login");

// Find open tickets
List<SupportTicket> open = searchIndex.query("status:OPEN");

// High priority tickets
List<SupportTicket> urgent = searchIndex.query("priority:HIGH");

// Tickets assigned to specific agent
List<SupportTicket> myTickets = searchIndex.query("assignee:agent123");

// Combine filters
List<SupportTicket> urgentOpen = searchIndex.query("status:OPEN AND priority:HIGH");

Search application logs or audit trails.

public class LogEntry
{
    private long id;
    private String level;
    private String message;
    private String source;
    private String traceId;
    private long timestamp;
    // ...
}

public class LogDocumentPopulator extends DocumentPopulator<LogEntry>
{
    @Override
    public void populate(Document document, LogEntry entry)
    {
        document.add(createStringField("level", entry.getLevel()));
        document.add(createTextField("message", entry.getMessage()));
        document.add(createStringField("source", entry.getSource()));
        document.add(createStringField("traceId", entry.getTraceId()));
        document.add(createLongField("timestamp", entry.getTimestamp()));
    }
}
// Search for errors
List<LogEntry> errors = searchIndex.query("level:ERROR");

// Search by message content
List<LogEntry> nullPointers = searchIndex.query("message:NullPointerException");

// Filter by source
List<LogEntry> authLogs = searchIndex.query("source:AuthService");

// Trace a specific request
List<LogEntry> trace = searchIndex.query("traceId:abc123");

// Time range query
long oneHourAgo = System.currentTimeMillis() - 3600000;
Query recentQuery = LongPoint.newRangeQuery("timestamp", oneHourAgo, Long.MAX_VALUE);
List<LogEntry> recentLogs = searchIndex.query(recentQuery);

Multi-Language Content

For multilingual content, use language-specific analyzers.

public class GermanAnalyzerCreator extends AnalyzerCreator
{
    @Override
    public Analyzer create()
    {
        return new GermanAnalyzer();
    }
}

// German content index
LuceneContext<Article> germanContext = LuceneContext.New(
    DirectoryCreator.MMap(Paths.get("/data/german-index")),
    new GermanAnalyzerCreator(),
    new ArticleDocumentPopulator()
);

For content in multiple languages, consider:

  1. Separate indexes per language - Best accuracy, more complex setup

  2. Language field with standard analyzer - Simpler, less accurate for non-English

  3. ICU analyzer - Good multilingual support

Combining with Bitmap Index

Use Lucene for full-text search and Bitmap for exact filtering.

// Setup both indexes
GigaMap<Product> products = GigaMap.New();

// Lucene for text search
LuceneIndex<Product> textSearch = products.index().register(
    LuceneIndex.Category(LuceneContext.New(new ProductDocumentPopulator()))
);

// Bitmap for exact filtering
IndexerString<Product> categoryIndexer = new IndexerString<>()
{
    @Override
    protected String getString(Product p) { return p.getCategory(); }
};
products.index().bitmap().add(categoryIndexer);

// Query: Full-text search + category filter
List<Product> textResults = textSearch.query("name:wireless");
List<Product> filtered = products.query(categoryIndexer.is("Electronics"))
    .filter(textResults::contains)
    .toList();

Search-as-You-Type

For autocomplete or search-as-you-type features, use wildcard queries.

public List<Product> searchAsYouType(String input, int limit)
{
    if (input == null || input.length() < 2)
    {
        return Collections.emptyList();
    }

    // Escape special characters and add wildcard
    String sanitized = QueryParser.escape(input.toLowerCase());
    String query = "name:" + sanitized + "*";

    return searchIndex.query(query, limit);
}
Wildcard queries can be slow on large indexes. Consider using edge n-grams for better performance in production.

Configuration Summary

Use Case Storage Analyzer Notes

Product Catalog

MMap

Standard

Persistent, supports numeric ranges

Article/Blog

MMap

Standard

Date filtering via long field

Customer Search

MMap

Standard

Case-insensitive email matching

Support Tickets

MMap

Standard

Status/priority exact match

Log Search

ByteBuffers

Standard

In-memory for recent logs

Multi-Language

MMap

Language-specific

Separate indexes recommended