Skip to main content

AEM Search using Apache SOLR

Solr is a search server built on top of Apache Lucene, an open source, Java-based, information retrieval library. It is designed to drive powerful document retrieval applications — wherever you need to serve data to users based on their queries, Solr can work for you.

In simple terms, Solr works similar to database where we can store data, query data for search functionality.

Major features:

  • full-text search
  • hit highlighting
  • faceted search
  • real-time indexing
  • dynamic clustering
  • database integration
  • NoSQL features
  • rich document handling.

Objective:

  • Learn how to create a custom AEM search component using author dialogs.
  • Understand the role of Sling Servlets and Sling service to index pages and delete indexes from Solr and make a call and get search results from solr.

Steps to set up Solr:

Step 1: To install Solr server, you need to have Java 1.8/11 installed in you machine.

Step 2: Download and install the Solr server 8.x above Ex:- I downloaded (solr-8.2.0.zip ) from the following

URL: http://archive.apache.org/dist/lucene/solr/

AEM Search using Apache SOLR

Step 3: Unzip the zip file.

Step 4: After unzipping file structure of solr seems like

AEM Search using Apache SOLR

Step 5: Go to the bin folder and run the below command to start the Solr server.

solr start -e cloud -noprompt

AEM Search using Apache SOLR

Step 6: Once the server starts, you will see the message in the command prompt. Solr is started on 8983 port.

Step 7: Open the browser and verify the URL

http://localhost:8983/solr/#/

AEM Search using Apache SOLR

Step 8: Below code to be implemented to index content in solr and component

    • 1) Implement servlet to index content to solr

package com.adobe.aem.core.servlets;

import java.io.IOException;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import org.osgi.framework.Constants;
import org.apache.sling.api.servlets.HttpConstants;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONException;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.aem.core.SolrSearchService;

import com.adobe.aem.core.SolrServerConfiguration;

/**
 *
 * This servlet acts as a bulk update to index content pages and assets to the
 * configured Solr server
 *
 */

@Component(service=Servlet.class,
        property={
                Constants.SERVICE_DESCRIPTION + "=Solr Index Servlet",
                "sling.servlet.methods=" + HttpConstants.METHOD_POST,
                "sling.servlet.paths="+ "/bin/solr/push/pages"
           })
public class IndexContentToSolr extends SlingAllMethodsServlet {

   private static final long serialVersionUID = 1L;
   private static final Logger LOG = LoggerFactory
         .getLogger(IndexContentToSolr.class);

   @Reference
   SolrSearchService solrSearchService;
   @Reference
   SolrServerConfiguration solrConfigurationService;

   @Override
   protected void doGet(SlingHttpServletRequest request,
         SlingHttpServletResponse response) throws ServletException,
         IOException {
      doPost(request, response);

   }

   @Override
   protected void doPost(SlingHttpServletRequest request,
         SlingHttpServletResponse response) throws ServletException,
         IOException {
      response.setContentType("text/html");
      String indexType = request.getParameter("indexType");
      final String protocol = solrConfigurationService.getSolrProtocol();
      final String serverName = solrConfigurationService.getSolrServerName();
      final String serverPort = solrConfigurationService.getSolrServerPort();
      final String coreName = solrConfigurationService.getSolrCoreName();
      final String pagesResourcePath = solrConfigurationService.getContentPagePath();

      String URL = protocol + "://" + serverName + ":" + serverPort+ "/solr/" + coreName;

      //Create an HTTPSolrClient instance
      HttpSolrClient server = new HttpSolrClient(URL);
        LOG.info("server value---"+ server);

      if (indexType.equalsIgnoreCase("indexpages")) {
         try {
            JSONArray indexPageData = solrSearchService.crawlContent(pagesResourcePath, "cq:PageContent");

            boolean resultindexingPages = solrSearchService.indexPagesToSolr(indexPageData, server);
                LOG.info("index value---"+resultindexingPages);
            if (resultindexingPages) {
               response.getWriter()
                     .write("<h3>Successfully indexed content pages to Solr server </h3>");
            } else {
               response.getWriter().write("<h3>Something went wrong</h3>");
            }
         } catch (Exception e) {
            LOG.error("Exception due to", e);
            response.getWriter()
                  .write("<h3>Something went wrong. Please make sure Solr server is configured properly in Felix</h3>");
         }

      } else {
         response.getWriter().write("<h3>Something went wrong</h3>");
      }

   }

}

 

  • 2) Service interface

package com.adobe.aem.core;

import com.day.cq.search.result.SearchResult;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.JSONObject;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;

import javax.jcr.RepositoryException;
import java.io.IOException;

public interface SolrSearchService {

   JSONArray crawlContent(String resourcePath, String resourceType);

   JSONArray createPageMetadataArray(SearchResult results)
         throws RepositoryException;

   JSONObject createPageMetadataObject(Resource pageContent);

   boolean indexPageToSolr(JSONObject indexPageData, HttpSolrClient server)
         throws JSONException, SolrServerException, IOException;

   boolean indexPagesToSolr(JSONArray indexPageData, HttpSolrClient server)
         throws JSONException, SolrServerException, IOException;

}

 

      • 3) Service impl class to implement the service interface

package com.adobe.aem.core.impl;

import java.io.IOException;
import java.util.*;
import java.util.HashMap;
import java.util.Map;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.apache.commons.lang3.StringUtils;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.JSONObject;
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.common.SolrInputDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.aem.core.SolrSearchService;
import com.adobe.aem.core.utils.SolrUtils;
import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.Hit;
import com.day.cq.search.result.SearchResult;

@Component
public class SolrSearchServiceImpl implements SolrSearchService {

   private static final Logger LOG = LoggerFactory
         .getLogger(SolrSearchServiceImpl.class);

   @Reference
   private QueryBuilder queryBuilder;

   @Reference
   private SlingRepository repository;

   /**
    * This method takes path and type of resource to perform search in JCR
    *
    * @param resourcePath
    * @param resourceType
    * @return JSONArray with resources metadata
    */
  
@Override
   public JSONArray crawlContent(String resourcePath, String resourceType) {

      Map<String, String> params = new HashMap<String, String>();
      params.put("path", resourcePath);
      params.put("type", resourceType);
      params.put("p.offset", "0");
      params.put("p.limit", "10000");

      Session session = null;

      try {
         session = repository.loginAdministrative(null);
         Query query = queryBuilder.createQuery(
               PredicateGroup.create(params), session);

         SearchResult searchResults = query.getResult();

         LOG.info("Found '{}' matches for query",
               searchResults.getTotalMatches());
         if (resourceType.equalsIgnoreCase("cq:PageContent")) {
            return createPageMetadataArray(searchResults);
         }

      } catch (RepositoryException e) {
         LOG.error("Exception due to", e);
      } finally {
         if (session.isLive() || session != null) {
            session.logout();
         }
      }
      return null;

   }

   /**
    * This method takes search result of content pages and creates a JSON array
    * object with properties
    *
    * @param results
    * @return
   
* @throws RepositoryException
    */
  
@Override
   public JSONArray createPageMetadataArray(SearchResult results)
         throws RepositoryException {
      JSONArray solrDocs = new JSONArray();
      for (Hit hit : results.getHits()) {
         Resource pageContent = hit.getResource();
         ValueMap properties = pageContent.adaptTo(ValueMap.class);
         String isPageIndexable = properties.get("notsolrindexable",
               String.class);
         if (null != isPageIndexable && isPageIndexable.equals("true"))
            continue;
         JSONObject propertiesMap = createPageMetadataObject(pageContent);
         solrDocs.put(propertiesMap);
      }

      return solrDocs;

   }

   /**
    * This method creates JSONObject which has all the page metadata which is used to index in Solr server
    * @param It takes resource of type cq:PageContent to extract the page metadata
    * @return Json object with page's metadata
    */
  
@Override
   public JSONObject createPageMetadataObject(Resource pageContent) {
      Map<String, Object> propertiesMap = new HashMap<String, Object>();
      //propertiesMap.put("id", pageContent.getParent().getPath());
      //propertiesMap.put("url", pageContent.getParent().getPath() + ".html");
      ValueMap properties = pageContent.adaptTo(ValueMap.class);
      String pageTitle = properties.get("jcr:title", String.class);
      if (StringUtils.isEmpty(pageTitle)) {
         pageTitle = pageContent.getParent().getName();
      }
      propertiesMap.put("title", pageTitle);
      propertiesMap.put("description", SolrUtils.checkNull(properties.get(
            "jcr:description", String.class)));
      propertiesMap.put("publishDate", SolrUtils.checkNull(properties.get(
            "publishdate", String.class)));
      propertiesMap.put("body","");
      /*final Date lastModified = properties.get(
        "cq:lastModified", Date.class);
        propertiesMap.put("lastModified", SolrUtils.convertToUtc(lastModified));*/

      //propertiesMap.put("lastModified", SolrUtils.solrDate(properties.get(
      // "cq:lastModified", Calendar.class)));
      propertiesMap.put("contentType", "page");
      propertiesMap.put("tags", SolrUtils.getPageTags(pageContent));
      return new JSONObject(propertiesMap);
   }


   /**
    * This method connects to the Solr server and indexes page content using Solrj api. This is used by bulk update handler (servlet)
    * @param Takes Json array and iterates over each object and index to solr
    * @return boolean true if it indexes successfully to solr server, else false.
    */
  
@Override
   public boolean indexPagesToSolr(JSONArray indexPageData,HttpSolrClient server) throws JSONException, SolrServerException,
         IOException {

      if (null != indexPageData) {
         LOG.info("index page sto solr");

         for (int i = 0; i < indexPageData.length(); i++) {
            JSONObject pageJsonObject = indexPageData.getJSONObject(i);
            SolrInputDocument doc = createPageSolrDoc(pageJsonObject);
            server.add(doc);
         }
         server.commit();
         return true;
      }

      return false;
   }

   /**
    * This method connects to the Solr server and indexes page content using Solrj api. This is used by transport handler
    * @param Takes Json object and index to solr
    * @return boolean true if it indexes successfully to solr server, else false.
    */
  
@Override
   public boolean indexPageToSolr(JSONObject indexPageData,HttpSolrClient server) throws JSONException, SolrServerException,
         IOException {
      if (null != indexPageData) {
         SolrInputDocument doc = createPageSolrDoc(indexPageData);
         server.add(doc);
         server.commit();
         return true;
      }

      return false;
   }


   private SolrInputDocument createPageSolrDoc(JSONObject pageJsonObject) throws JSONException {

      SolrInputDocument doc = new SolrInputDocument();
      doc.addField("title", pageJsonObject.get("title"));
      doc.addField("body", pageJsonObject.get("body"));
      doc.addField("description", pageJsonObject.get("description"));
      doc.addField("contentType", pageJsonObject.get("contentType"));
      doc.addField("tags", pageJsonObject.get("tags"));
      return doc;

   }


}

      • 4) Solr configuration interface

·       package com.adobe.aem.core;

public interface SolrServerConfiguration {
  
  
   public String getSolrProtocol();
   
   public String getSolrServerName() ;

   public String getSolrServerPort() ;

   public String getSolrCoreName() ;
  
   public String getContentPagePath() ;

}

 

package com.adobe.aem.core;

import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;

 
@ObjectClassDefinition(name = "AEM Solr Search - Solr Configuration Service", description = "Service Configuration")
public @interface MySimpleService {
    
   @AttributeDefinition(name = "Protocol", defaultValue ="http", description = "Configuration value")
    String protocolValue();
  
  
   @AttributeDefinition(name = "Solr Server Name", defaultValue ="localhost", description = "Server name or IP address")
    String serverName();
   
   @AttributeDefinition(name = "Solr Server Port", defaultValue ="8983", description = "Server port")
    String serverPort();
  
   @AttributeDefinition(name = "Solr Core Name", defaultValue ="collection", description = "Core name in solr server")
    String serverCollection();
  
   @AttributeDefinition(name = "Content page path", defaultValue ="/content/we-retail", description = "Content page path from where solr has to index the pages")
    String serverPath();
    

      • 5) Delete index in solr

package com.adobe.aem.core.servlets;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.Servlet;
import org.osgi.framework.Constants;
import org.apache.sling.api.servlets.HttpConstants;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;



/**
 *
 * @author kavarana
 * This servlet deletes all the indexes from the configured Solr server
 *
 */
@Component(service=Servlet.class,
        property={
                Constants.SERVICE_DESCRIPTION + "=Solr Delete Index",
                "sling.servlet.methods=" + HttpConstants.METHOD_POST,
                "sling.servlet.paths="+ "/bin/solr/delete/all/indexes"
           })    
public class DeleteIndexesFromSolr extends SlingAllMethodsServlet {
   private static final long serialVersionUID = 1L;
   private static final Logger LOG = LoggerFactory
         .getLogger(DeleteIndexesFromSolr.class);

  
   @Override
    protected void doPost(final SlingHttpServletRequest reqest,
            final SlingHttpServletResponse response) throws ServletException, IOException {
      response.setContentType("text/html");
      String protocol = "http";
      String serverName = "localhost";
      String serverPort = "8983";
      String coreName = "collection";
      String URL = protocol + "://" + serverName + ":" + serverPort
            + "/solr/" + coreName;
      HttpSolrClient server = new HttpSolrClient(URL);
      try {
         server.deleteByQuery("*:*");
         server.commit();
         server.close();
         response.getWriter().write("<h3>Deleted all the indexes from solr server </h3>");
      } catch (SolrServerException e) {
         LOG.error("Exception due to", e);
      }
     
       
    }
}

Component implementation under ui.apps

AEM Search using Apache SOLR

Solrsearch.html below code

<script src="https://code.jquery.com/jquery-3.1.0.js" integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk=" crossorigin="anonymous"></script> 
<h4>This is a basic search component which connects solr to fetch search results</h4>
<input type="text" id="search-box" />
<input type="button" id="search-button" value="Search"/>
<div id="search-result"></div>
<br>
<script type="application/javascript">
    $( document ).ready(function() {
        $("#search-button").click(function(){
            $("#search-result").empty();
            if($("#search-box").val() == null){
                alert("please enter the search term");
            }
            else{
                var searchTerm = $("#search-box").val();
                 $.ajax({
                     url: "http://localhost:8983/solr/collection/select?q=title%3A"+searchTerm+"&wt=json",
                     dataType: "jsonp",
                     jsonp: 'json.wrf',
                     success: function(result){
                         console.log(result);
                         var numResultsFound = result.response.numFound;
                         if( numResultsFound > 0){
                             $("#search-result").append("<h4> Search results: </h4>");
                             $("#search-result").append("<h5>"+numResultsFound+" found for the search term "+searchTerm +"</h5>");
                             $.each(result.response.docs, function( index, value ) {
                                 var link = "<a href='"+value.url[0]+"'>"+value.title+"</a>";
                                 console.log(link);                                 
                                 $("#search-result").append(link+"<br>");                            
                             });
                         }
                         else{
                              $("#search-result").append("<h4> No results found for search term "+searchTerm+" </h4>");
                         }
                     },
                     error: function(){
                         $("#search-result").append("Something went wrong :( ");
                     }
                 });

            }
        });
    });
</script>

 

Content.xml file

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
    jcr:description="This is a basic solr search component which uses ajax to connect to solr server to fetch the data"
    jcr:primaryType="cq:Component"
    jcr:title="Solr Search"
    componentGroup="AemSolr2"/>

 

Create a folder and paste a code under this path - > /apps/AemSolr2/solr-index/components/content

AEM Search using Apache SOLR

Put below code in context.xml

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
    jcr:primaryType="cq:Page">
    <jcr:content
        jcr:primaryType="nt:unstructured"
        jcr:title="Solr Index Creation"
        sling:resourceType="granite/ui/components/shell/page"
        consoleId="solr-config">
        <head jcr:primaryType="nt:unstructured">
            <clientlibs
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/includeclientlibs"
                categories="[granite.ui.coral.foundation,solr.base]"/>
        </head>
        <title
            jcr:primaryType="nt:unstructured"
            jcr:title="Solr Index Creation"
            sling:resourceType="granite/ui/components/shell/title"/>
        <content
            jcr:primaryType="nt:unstructured"
            sling:resourceType="granite/ui/components/coral/foundation/container"
            margin="{Boolean}true">
            <items jcr:primaryType="nt:unstructured">
                <columns
                    jcr:primaryType="nt:unstructured"
                    sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"
                    margin="{Boolean}true">
                    <items jcr:primaryType="nt:unstructured">
                        <column
                            jcr:primaryType="nt:unstructured"
                            sling:resourceType="granite/ui/components/coral/foundation/container"
                            margin="{Boolean}true">
                            <items jcr:primaryType="nt:unstructured">
                                <container
                                    jcr:primaryType="nt:unstructured"
                                    sling:resourceType="granite/ui/components/coral/foundation/container"
                                    margin="{Boolean}true">
                                    <items jcr:primaryType="nt:unstructured">
                                        <heading
                                            granite:class="coral-Heading coral-Heading--2"
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/heading"
                                            level="{Long}2"
                                            text="Create/Delete Index"/>
                                        <well
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/well"
                                            margin="{Boolean}true">
                                            <items jcr:primaryType="nt:unstructured">
                                                <container
                                                    granite:id="myForm"
                                                    jcr:primaryType="nt:unstructured"
                                                    sling:resourceType="granite/ui/components/coral/foundation/form"
                                                    foundationForm="{Boolean}true"
                                                    loadingMask="{Boolean}true"
                                                    margin="{Boolean}true"
                                                    maximized="{Boolean}true"
                                                    style="vertical">
                                                    <items jcr:primaryType="nt:unstructured">
                                                        <heading
                                                            granite:class="coral-Heading coral-Heading--2"
                                                            jcr:primaryType="nt:unstructured"
                                                            sling:resourceType="granite/ui/components/coral/foundation/heading"
                                                            level="{Long}2"
                                                            text="Index Pages"/>
                                                        <gtmContainerId
                                                            granite:id="indexType"
                                                            jcr:primaryType="nt:unstructured"
                                                            sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                                            fieldLabel="Index Pages"
                                                            name="./gtmContainerId"
                                                            required="{Boolean}true"
                                                            value="indexpages"/>
                                                        <submitButton
                                                            granite:id="btnSubmit"
                                                            jcr:primaryType="nt:unstructured"
                                                            sling:resourceType="granite/ui/components/coral/foundation/button"
                                                            text="Index Pages"
                                                            type="submit"/>
                                                    </items>
                                                </container>
                                                <container1
                                                    granite:id="myDeleteForm"
                                                    jcr:primaryType="nt:unstructured"
                                                    sling:resourceType="granite/ui/components/coral/foundation/form"
                                                    foundationForm="{Boolean}true"
                                                    loadingMask="{Boolean}true"
                                                    margin="{Boolean}true"
                                                    maximized="{Boolean}true"
                                                    style="vertical">
                                                    <items jcr:primaryType="nt:unstructured">
                                                        <heading
                                                            granite:class="coral-Heading coral-Heading--2"
                                                            jcr:primaryType="nt:unstructured"
                                                            sling:resourceType="granite/ui/components/coral/foundation/heading"
                                                            level="{Long}2"
                                                            text="Delete Pages"/>
                                                        <submitButton
                                                            granite:id="btnDSubmit"
                                                            jcr:primaryType="nt:unstructured"
                                                            sling:resourceType="granite/ui/components/coral/foundation/button"
                                                            text="Delete Pages"
                                                            type="submit"/>
                                                    </items>
                                                </container1>
                                            </items>
                                        </well>
                                    </items>
                                </container>
                            </items>
                        </column>
                    </items>
                </columns>
            </items>
        </content>
    </jcr:content>
</jcr:root>

 

Step 9: Go to the AemSolr2 folder and run below the maven command to deploy code.

Mvn clean install -P autoInstallPackage

AEM Search using Apache SOLR

Check below packages installed in AEM CRXDE

https://localhost:4502/crx/de

AEM Search using Apache SOLR

 

 

Step 10: Now go to solr web client and create a collection: This collection is for a single search index. Follow the below steps to create an index in solr.

From the web client, select Collection

AEM Search using Apache SOLR

Click Add Collection

AEM Search using Apache SOLR

provide the name of the collection "collection". Choose the config list from dropdown. I am using gettingstarted. You can provide a shard number according to your requirement. I am keeping it 1 at this moment.

You can provide a replication factor. By default, it is 1.

AEM Search using Apache SOLR

Click add a collection. You can see the collection is created.

AEM Search using Apache SOLR

There are a lot of options available like you can delete collection by clicking the "Delete" button or you can also create an alias. We are just creating collection as part of this article.

We are done at solr side. Now we will do some configurations at the AEM side.

Step 11: Configure AEM to Solr:

    • Go to localhost:4502/system/console/bundles
    • Select configuration from bundles tab
    • Or directly go to link localhost:4502/system/console/configMgr
p>1) Search for "AEM Solr Search - Solr Configuration" service and enter the  following values:

 

    Protocol: http

    Solr Server Name: localhost

    Solr Server Port: 8983 (port number of your solr web client)

    Solr Core Name: collection ( references the collection you created)

    Content page path: /content/www/us/en

AEM Search using Apache SOLR

2) Search "Oak Solr remote" in configuration and check solr details. Check the port number of solr in the Solr HTTP URL. The rest is fine. Click Save.

AEM Search using Apache SOLR

3) Search "oak solr server provider" and select remote solr from the drop-down.

As our Solr is installed separately, It is not embedded so select "Remote Solr"

AEM Search using Apache SOLR

Now we are good to go!

Now create an index in Solr. For this, we have IndexContentToSolr java servlet which makes a connection to solr and creates an index.

For code brevity, this code example uses repository.loginAdministrative(null) method. This is used simply to keep the code shorter. If you are using this in Production, the recommended way is to create a system user and use the Sling Mapping Service. In order to run this example without creating system user, you can whitelist this call. It is not recommanded to use this. Please create appropriate system user and use sling mapping.


To Bypass login request, enable bypass. Go to configMgr Search "Sling Login Admin whitelist" and click the checkbox and save. ( for testing purpose only)

Login Admin whitelist" and click the checkbox and save. ( for testing purpose only)

AEM Search using Apache SOLR

For UI, I have created a basic component that is used to create indexing and delete indexing. Open http://localhost:4502/apps/AemSolr2/solr-index/components/content/solr-config.html

AEM Search using Apache SOLR

Click the "Index Pages" button. The default value is already populated to the text field which is "indexpages". Pages are successfully indexed.

Response Message: "Response is successfully indexed pages to solr server".

Index creation is done on the properties that you specified in your java file. For example, we did on below properties only. It will do indexing on id, title, etc. properties that we have added to create an index if present in page properties.

Check solr web client to check indexes. Click collection Selection drop down from the left panel and select your collection name. In our case, it is "collection"

AEM Search using Apache SOLR

Check solr web client to check indexes. Click collection Selection drop down from the left panel and select your collection name. In our case, it is "collection"

AEM Search using Apache SOLR

Now Select Query from the left panel and click execute a query. All indexed pages appear as a result.

AEM Search using Apache SOLR

View Solr results in AEM

In the codebase, we have a component named "solrsearch". Go to  /apps/AemSolr2/components/content/solrsearch to see component details.

Add below lines on top of the HTML file of /apps/AemSolr2/components/content/solrsearch/solrsearch.html

<script src="https://code.jquery.com/jquery-3.1.0.js" integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk=" crossorigin="anonymous"></script>  

I have already added this line to my component.

Now open any page for eg. http://localhost:4502/editor.html/content/AemSolr2/en.html. Click to drag component. You will see the "+" icon to add a component. 

AEM Search using Apache SOLR

Open in preview/publish view

Below is the result.

AEM Search using Apache SOLR

AEM Search using Apache SOLR

 Search is working in AEM with apache solr.

You can search in apache solr to check the result is the same as AEM search or not.

Go to solr web client and in the query enter title/id etc. on which you want to apply search and click execute the search. Let's search for "English" and the only title which has "Covid" keyword has appeared as a result.

Enter "Covid" in q place which is query string place.

AEM Search using Apache SOLR

You can delete the index that you have created earlier. Click "Delete index" to the component and you are done.

AEM Search using Apache SOLR

Index Deleted in Solr web server.

AEM Search using Apache SOLR

Stop the Solr server. Go to the bin folder of Solr and Run 

solr stop -all.

AEM Search using Apache SOLR

Hope you liked the article. Please reach out to digital group: digital.interactive@coforge.com for any query.

Let’s engage