This document provides an overview of Omnisearch in AEM 6.2, including how to use it, add new locations, and implement a custom Omnisearch handler. Omnisearch provides a unified search experience across AEM authoring tools and content. Key points covered include how to build queries for search results, suggestions, and spell check, as well as configure the UI display of search locations and results. The presentation includes code examples for implementing a custom Omnisearch handler that searches content fragments. It concludes with a demonstration and overview of potential future enhancements.
#evolverocks17
@Component
@Service
public final classContentFragmentOmniSearchHandler
implements OmniSearchHandler {
@Override
public Resource getModuleConfig(ResourceResolver resourceResolver) {
return resourceResolver.getResource(
"/apps/aem-omnisearch-content-fragments/content/metadata");
}
@Override
public String getID() {
return "custom-cfm";
}
}
START OF IMPLEMENTATION
18.
#evolverocks18
getResults()
Return the actualsearch results
getSuggestions()
Return a Query to get the list of suggestions
getSpellCheck()
Return a Query to get the list of spell check suggestions
getPredicateSuggestions()
Get a list of predicate suggestions based on a search term
SEARCH METHODS
19.
#evolverocks 19
Requires configurationof Lucene indexes
e.g. /oak:index/damAssetLucene
Properties can have these two flags:
useInSuggest
useInSpellcheck
Suggestion list is updated every 10 minutes by default, but configurable.
Path restriction support is limited
Property restriction support is non-existing
OAK SUGGESTIONS & SPELL CHECK
A BRIEF DIGRESSION
20.
#evolverocks20
@Override
public SearchResult getResults(ResourceResolverresourceResolver,
Map<String, Object> predicateParameters, long limit, long offset) {
Map<String, String> predicates = new HashMap<String, String>();
predicates.put("path", DamConstants.MOUNTPOINT_ASSETS);
predicates.put("type", DamConstants.NT_DAM_ASSET);
predicates.put("property", "jcr:content/contentFragment");
predicates.put("property.value", "true");
if (predicateParameters.containsKey("fulltext")) {
String[] ft = (String[]) predicateParameters.get("fulltext");
predicates.put("fulltext", ft[0]);
}
PredicateGroup predicatesGroup = PredicateGroup.create(predicates);
com.day.cq.search.Query query = queryBuilder.createQuery(predicatesGroup,
resourceResolver.adaptTo(Session.class));
if (limit != 0) {
query.setHitsPerPage(limit);
}
if(offset != 0) {
query.setStart(offset);
}
SearchResult queryResult = query.getResult();
return queryResult;
}
SEARCH METHOD
THE NAÏVE VERSION
21.
#evolverocks 21
boolean addedPath= false;
boolean addedType = false;
for (Map.Entry<String, Object> param : predicateParameters.entrySet()) {
if (param.getValue() instanceof String[]) {
String[] values = (String[]) param.getValue();
if (values.length == 1) {
if ((param.getKey().equals("path") || param.getKey().endsWith("_path"))
&& values[0].length() > 0) {
addedPath = true;
}
if (param.getKey().equals("type") || param.getKey().endsWith("_type")) {
addedType = true;
}
predicates.put(param.getKey(), values[0]);
}
}
}
if (!addedPath) {
predicates.put("path", DamConstants.MOUNTPOINT_ASSETS);
}
if (!addedType) {
predicates.put("type", DamConstants.NT_DAM_ASSET);
}
predicates.put("999_property", "jcr:content/contentFragment");
predicates.put("999_property.value", "true");
SEARCH METHOD
THE REAL VERSION
22.
#evolverocks 22
public QuerygetSuggestionQuery(ResourceResolver resourceResolver,
String term) {
String queryStr = "SELECT [rep:suggest()] FROM [dam:Asset] as s " +
" WHERE SUGGEST($term) AND ISDESCENDANTNODE([/content/dam])";
try {
Query query = createQuery(resourceResolver, term, queryStr);
return query;
} catch (RepositoryException e) {
log.error("Unable to create suggestions query", e);
return null;
}
}
SUGGESTIONS METHOD
23.
#evolverocks 23
@Override
public List<PredicateSuggestion>getPredicateSuggestions(
ResourceResolver resourceResolver, I18n i18n, String term) {
List<PredicateSuggestion> matchedPredicates =
new ArrayList<PredicateSuggestion>();
List<PredicateSuggestion> allPredicateSuggestions =
getAllPredicateSuggestions(resourceResolver);
for (PredicateSuggestion suggestion : allPredicateSuggestions) {
if (suggestion.getOptionTitle().toLowerCase().
contains(term.toLowerCase())) {
matchedPredicates.add(suggestion);
}
}
return matchedPredicates;
}
PREDICATE SUGGESTIONS
24.
#evolverocks24
• Control theUI of the search module
• Each handler needs to have one
• Default ones are at /libs/granite/omnisearch/content/metadata
MODULE CONFIGURATION NODES
25.
#evolverocks25
jcr:title
The display titleof the search location
listOrder
The order of the location
cardPath
The resource type used to render results in the card view
listItemPath
The resource type used to render results in the list view
clientlibs
Any custom clientlib that needs to be loaded when the location is shown. This is
typically used to handle custom actions when an item is selected.
MODULE CONFIG NODE PROPERTIES
26.
#evolverocks26
actions/selection
Actions that areloaded once an item from that
location is selected. Different actions could be
enabled during the Omnisearch here, as opposed
to the console.
views/list
View configuration that is used while in list view.
This is specially important for the List View
because allows to configure the columns that are
shown.
MODULE CONFIG NODE CHILD NODES
#evolverocks33
• Wizard support
•i.e. “Create” -> “Create Page” (suggestion) -> Create Page Wizard
• Tags as Global Predicate
• Recent Search Support
• Improved Save Search Support
FUTURE CONCEPTS
#23 The Spell check method is essentially the same using rep:spellcheck instead of rep:suggest. Note that you wouldn’t generally need to write this if you extended AbstractOmniSearchHandler
#26 You will also see icon and simpleCardPath in some of the OOTB nodes. These aren’t currently used but are planned optimizations in the future.