Building a Custom Index-Based Search in AEM 6.5 Using Oak Lucene and QueryBuilder

Building a Custom Index-Based Search in AEM 6.5 Using Oak Lucene and QueryBuilder

AEM

Searching is among the most needed functionalities in Adobe Experience Manager (AEM) projects, as it allows users to find all kinds of content, documentation, blogs or product pages. Nevertheless, the issue of slow performance can happen if the content repository is loaded with a lot of content as badly written queries can be used.

The content repository used by Adobe Experience Manager is Apache Jackrabbit Oak.This means that queries are executed by Oak with the help of indexes. In case indexes are not properly set, queries may have to traverse through thousands of nodes before returning the desired results.

This article will demonstrate how to create a custom index-based search with AEM 6.5:

  • Custom Oak Lucene Index
  • QueryBuilder API
  • OSGi Service
  • Sling Servlet
  • HTL Component
  • JavaScript Fetch API

By the end of this implementation, you'll understand how a search request flows from the UI to the repository and how a custom Oak index improves query performance.

Prerequisites

To follow this implementation, you should have:

  • Adobe Experience Manager 6.5 Author instance
  • Java 8 or Java 11
  • Apache Maven
  • Basic understanding of HTL and Sling
  • CRXDE Lite access

Project Overview

To demonstrate index-based searching, I created a Maven-based AEM project consisting of three modules:

  • core – Contains the business logic, OSGi service, and Sling Servlet.
  • ui.apps – Contains the HTL search component and Oak index definition.
  • ui.content – Provides sample content for testing search functionality.

search index structure

The project includes:

  • Custom Lucene Index (demoPageIndex)
  • IndexSearchService
  • SearchServlet
  • Search HTL Component
  • Sample Content Pages
  • REST Search API

search index architecure

This modular structure follows the standard AEM project architecture, keeping backend logic, UI components, and content packages separated.

Solution Architecture

The complete request flow is straightforward and demonstrates how different AEM layers work together.

User

HTL Search Component

JavaScript (Fetch API)

/bin/searchdemo

SearchServlet

IndexSearchService

QueryBuilder API

Oak Lucene Index

JCR Repository

Once the user types the keyword and presses Search, the JavaScript code sends an HTTP request to the Sling servlet. The servlet forwards the search request to an OSGi service which prepares QueryBuilder query. Oak evaluates the query using the custom Lucene index and returns matching pages to the UI as JSON.

Creating a Custom Oak Lucene Index

AEM executes queries efficiently only when an appropriate index is available. For this implementation, I created a custom Lucene index named demoPageIndex.

The index configuration includes:

  • type="lucene" for full-text indexing.
  • includedPaths="/content/demo-search" to restrict indexing to the demo content.
  • queryPaths="/content/demo-search" to ensure only relevant queries use this index.
  • async="[async,nrt]" to support asynchronous and near-real-time indexing.
  • indexRules for cq:Page.
  • Aggregation of jcr:content so page properties are searchable.

Instead of indexing the entire repository, the index is scoped only to the required content path, reducing indexing overhead and improving query performance.

search index crxde

Building the Search Service with QueryBuilder

The core search logic resides inside IndexSearchService.

Instead of manually traversing repository nodes, the service creates a QueryBuilder query using predicates such as:

  • path
  • type
  • fulltext
  • orderby
  • p.limit

These predicates allow the search to target only cq:Page nodes within a specific content path while leveraging the Lucene index for full-text search.

The service supports two search modes:

Full-Text Search

Searches indexed page titles and descriptions using the provided keyword.

Advanced Search

Supports additional features such as:

  • Result limiting
  • Sorting by last modified date
  • Search scoring

To improve resilience, the implementation also includes a fallback traversal search if QueryBuilder cannot execute the indexed query.

Exposing Search Through a Sling Servlet

To make the search functionality accessible, a Sling Servlet is registered at:

/bin/searchdemo

The servlet accepts parameters including:

Parameter Description
searchTerm Keyword entered by the user
searchPath Content path to search
searchType Full-text or advanced search
limit Maximum results

The servlet calls the search service only after verifying the request, which produces a JSON response that provides the results of the query.

By splitting the servlet from the service, the business logic is kept reusable, and this establishes a neat RESTful API for frontend applications.

Building the Search Component

The frontend is implemented using an HTL component with a lightweight JavaScript layer.

 search component

The component includes:

  • Search input
  • Search type selector
  • Configurable search path
  • Search button
  • Results section
  • Pagination controls

When a user makes a request to search, JavaScript calls the servlet asynchronously using the Fetch API.

The returned JSON gets processed and received without refreshing the screen, which ensures better usability.

Additional frontend features include:

  • Pagination
  • Loading indicator
  • Error handling
  • Highlighted search terms
  • Search score display for advanced search

Testing the Search Component

After deploying the project, the search component can be added to an AEM page and tested using sample content.

AEM search index ui

Searching for keywords such as AEM returns matching pages indexed under /content/demo-search.

The implementation displays:

  • Total result count
  • Highlighted keywords
  • Page description
  • Search score
  • Pagination controls

This demonstrates how the backend search service integrates seamlessly with the frontend component.

Verifying Deployment

Before testing the component, verify that the project bundle is active in the OSGi Console.

 adobe experience manager web console bundles

An active bundle confirms that the service and servlet have been successfully deployed and are available for processing search requests.

Key Features of the Implementation

This demo showcases several important AEM concepts:

  • Custom Oak Lucene Index
  • QueryBuilder-based searching
  • OSGi Service architecture
  • Sling Servlet REST API
  • HTL component development
  • AJAX-based search experience
  • Search result highlighting
  • Pagination support
  • Input validation
  • HTML sanitization
  • Structured JSON responses
  • Modular AEM project organization

Best Practices

While implementing search functionality in AEM, consider the following best practices:

  • Create custom indexes only for frequently executed queries.
  • Restrict indexes using includedPaths to avoid indexing unnecessary content.
  • Validate request parameters before executing queries.
  • Limit search results to improve response times.
  • Implement business rules through OSGi services instead of putting the logic into servlets.
  • Clean the content supplied by the end-user.
  • Employ the QueryBuilder Debugger and Explain Query features to ensure that you are using the required index.
  • Keep an eye on the index size and reindex only when it is necessary.

Conclusion

Efficient search in the context of any content-driven application is very significant and it’s where Adobe Experience Manager excels owing to its strong indexing features which are based on Apache Jackrabbit Oak search capabilities. The solution created using combination of custom Lucene index, QueryBuilder which is an OSGi service, Sling Servlet, and an HTL-based front end provides the complete modular search system.

While serving as a proof of concept in this project, the architecture discussed can be used in any enterprise implementations of AEM as well. Proper indexing, serviceable architecture, and clear separation of concerns will help to achieve better search results in an optimally maintainable and scalable code.

References

  • Adobe Experience Manager 6.5 QueryBuilder API Documentation
  • Adobe Experience Manager Oak Queries and Indexing Documentation
  • Apache Jackrabbit Oak Documentation
Written by
Vandit Photo Blogs 1

Vandit Shah

AEM Certified Developer

I’m Vandit Shah, an Adobe Certified AEM Developer at Arroact Technologies. I work with Adobe Experience Manager to build structured, scalable digital experiences that are both efficient to manage and consistent across channels. 

Alongside AEM, I focus on N&N Automation to streamline repetitive processes and improve how teams handle content and workflows. I’m interested in finding practical ways to reduce manual effort while keeping systems reliable and easy to maintain. 

My approach is straightforward - understand the requirement clearly, build with clean structure, and make sure the solution works smoothly in real-world use. I enjoy working on projects where thoughtful implementation can simplify complexity and create lasting value for both teams and end users. 

Related Blogs blue-line-vector-3

Building a Custom AEM Text Component with Dialog, HTL & Deployment
29 April 2613 min read
AEM
Building a Custom AEM Text Component with Dialog, HTL & Deployment
In AEM implementations in the real world, development of components that are reusable an…
Read More
AEM Workflow Explained: How It Works and Why It Matters
28 April 2618 min read
AEM
AEM Workflow Explained: How It Works and Why It Matters
Managing content through the Adobe Experience Manager (AEM) isn't simply a matter of crea…
Read More
Difference Between an Adobe Certification Badge and a Course Completion Certificate
12 March 2615 min read
AEM
Difference Between an Adobe Certification Badge and a Course Completion Certificate
If you’re learning Adobe Experience Manager (AEM), you’ve probably come across two things …
Read More