I'm working on refining an existing search functionality on the site. The search works but returns too many irrelevant results. I'm working on refining the search results to make them more relevant to the search term.
One of the configuration settings being used to create the search predicate is the Property allowedtypes. The current configuration has cq:Page and dam:Asset as the allowedtypes. From trial and error I found out that changing cq:Page to cq:PageContent ends up in better search results. I really don't know why this would be the case so I'd really like to know setting cq:PageContent as an allowedtype results in better search results. Also, for those who've worked on search functionality, what other suggestions would you give that can help finetune the search?
Solved! Go to Solution.
Views
Replies
Total Likes
Hello jamesm77050123
Any further tweaks to the query itself might now be scalable, or efficient. For example, using jcr:like will impact your performance, and I think the only tweak you can make being at query level is something like
"Sorry we didn't find any results for your searched term.
You can try changing the scope of the search term by adding an asterisk, such as bank* fee*, or wrapping your search in quotes and try again."
And a better alternative would be to try exploring the advanced search options for an index itself. For example, there are synonyms available for an index where what you basically have to do is figure out the index used by your query, and add an analyzer to your index with something called "Synonyms". In essence, you create a file, list some possible synonyms for your commonly searched terms and the index will now analyze any available synomyms for the search term input by the user.
It's true that this will be some manual work but considering your business and commonly used search terms, you can start this file with a few common words. You can read about this in Jackrabbit Oak – Lucene Index and look for the word "Synonym".
While the Synonyms is some manual work, Suggestions and Spellcheck in the index are also available. You can take a look at the link Jackrabbit Oak – Lucene Index for further insight into this.
Some detailed explanation is also listed in https://aemcorner.com/search-in-aem/
I hope this helps.
Best Regards,
Aneet Arora
Views
Replies
Total Likes
Please provide more details on your search implementation. What API are you using - QueryBuilder? Can you provide the syntax you are using for the search. This way - the community can help you better.
Views
Replies
Total Likes
Hi,
Can you check which index is getting used for your both queries at
Operations Dashboard https://helpx.adobe.com/experience-manager/6-3/sites/deploying/using/best-practices-for-queries-and-...
Please share your example query as well
Views
Replies
Total Likes
Below is the search config
Below is the query
ROOT=group: limit=30, guessTotal=true, offset=0[
{1_path=path: path=/content/site/desktop/gt/en}
{2_group=group: or=true[
{1_fulltext=fulltext: fulltext=tax}
]}
{3_group=group: not=true, or=true[
{1_path=path: path=excludedpaths}
{2_property=property: property=jcr:content/sling:resourceType, value=foundation/components/redirect}
{3_property=property: property=jcr:content/sling:resourceType, value=site/components/pages/sightly/coza/desktop/listingpage}
{4_property=property: property=jcr:content/sling:resourceType, value=site/components/pages/sightly/coza/desktop/flexilistingpage}
{5_property=property: property=jcr:content/sling:resourceType, value=site/components/pages/sightly/coza/desktop/thankyoupage}
{6_property=property: property=jcr:content/sling:resourceType, value=site/components/pages/sightly/coza/desktop/errorpage}
{7_property=property: property=jcr:content/sling:resourceType, value=site/components/pages/sightly/coza/desktop/landingpage}
{8_property=property: property=jcr:content/sling:resourceType, value=site/components/pages/sightly/coza/desktop/formintroductionpage}
{9_property=property: property=jcr:content/sling:resourceType, value=site/components/pages/sightly/coza/desktop/listingpagegeneric}
{10_property=property: property=jcr:content/excludeFromSearch, value=true}
]}
{4_group=group: or=true[
{1_path=path: path=}
]}
{5_group=group: or=true[
{1_group=group: or=false[
{1_type=type: type=cq:Page}
]}
{2_group=group: or=false[
{1_type=type: type=dam:Asset}
{2_group=group: or=true[
{1_property=property: property=jcr:content/metadata/dc:format, value=application/pdf}
]}
]}
]}
]
below the main method being executed for search.
private SearchResult executeSearch(String resourcePath, String[] searchTags, String[] orTags, String searchPath, String[] resultTypes, long offset, long hitsPerPage, Session session, Predicate fulltextPredicate) {
//todo: Handle searchTag and searchPath
SearchFactoryConfig config = getSearchConfig(resourcePath);
if (config == null) {
log.error("no configuration found for the path {}", resourcePath);
return nulpl;
}
try {
//Search query description will be passed as a hash map
Map<String, String> map = new HashMap<String, String>();
map.put("p.guessTotal", "true");
//map.put("orderby", " @jcr:title");
boolean searchingForTags = false;
PredicateGroup mainGroup = PredicateGroup.create(map);
log.info("resultTypes init = " + resultTypes);
//mainGroup.setAllRequired(false);
if (searchPath != null && !searchPath.isEmpty()) {
mainGroup.add(new Predicate("path").set("path", searchPath));
}
PredicateGroup andTagsroup = new PredicateGroup();
andTagsroup.setAllRequired(true);
if (searchTags != null && searchTags.length > 0) {
for (String searchTag : searchTags) {
if (!searchTag.isEmpty()) {
andTagsroup.add(new Predicate("tagid").set("tagid", searchTag).set("property", "jcr:content/cq:tags"));
}
}
if (andTagsroup.size() > 0) {
mainGroup.add(andTagsroup);
}
}
PredicateGroup includedGroup = new PredicateGroup();
includedGroup.setAllRequired(false);
if (orTags != null && orTags.length > 0) {
for (String orTag : orTags) {
if (!orTag.isEmpty()) {
includedGroup.add(new Predicate("tagid").set("tagid", orTag).set("property", "jcr:content/cq:tags"));
}
}
}
if (fulltextPredicate != null) {
includedGroup.add(fulltextPredicate);
}
mainGroup.add(includedGroup);
PredicateGroup excludedGroup = new PredicateGroup();
excludedGroup.setNegated(true);
excludedGroup.setAllRequired(false);
for (Iterator<String> i = config.getExcludedPaths().iterator(); i.hasNext(); ) {
String excludedPath = i.next();
if (!excludedPath.isEmpty()) {
excludedGroup.add(new Predicate("path").set("path", excludedPath));
}
}
for (Iterator<String> i = config.getExcludedTypes().iterator(); i.hasNext(); ) {
String excludedType = i.next();
Predicate propertyPredicate = new Predicate("property").set("property", "jcr:content/sling:resourceType");
propertyPredicate.set("value", excludedType);
excludedGroup.add(propertyPredicate);
}
Predicate propertyPredicate = new Predicate("property").set("property", "jcr:content/excludeFromSearch");
propertyPredicate.set("value", "true");
excludedGroup.add(propertyPredicate);
mainGroup.add(excludedGroup);
PredicateGroup allowedPathsGroup = new PredicateGroup();
allowedPathsGroup.setAllRequired(false);
PredicateGroup allowedTypesGroup = new PredicateGroup();
allowedTypesGroup.setAllRequired(false);
if (searchingForTags) {
for (Iterator<String> i = config.getTagPaths().iterator(); i.hasNext(); ) {
String tagPath = i.next();
allowedPathsGroup.add(new Predicate("path").set("path", tagPath));
}
allowedTypesGroup.add(new Predicate("type").set("type", "cq:Tag"));
} else {
for (Iterator<String> i = config.getAllowedPaths().iterator(); i.hasNext(); ) {
String allowedPath = i.next();
allowedPathsGroup.add(new Predicate("path").set("path", allowedPath));
}
for (Iterator<String> i = config.getAllowedTypes().iterator(); i.hasNext(); ) {
String allowedType = i.next();
PredicateGroup allowedTypeGroup = new PredicateGroup();
allowedTypeGroup.setAllRequired(true);
if (allowedType.contentEquals("dam:Asset") && config.getAssetMimeTypes().size() > 0) {
PredicateGroup mimeTypesGroup = new PredicateGroup();
mimeTypesGroup.setAllRequired(false);
for (String assetMimeType : config.getAssetMimeTypes()) {
Predicate mimeTypePredicate = new Predicate("property").set("property", "jcr:content/metadata/dc:format");
mimeTypePredicate.set("value", assetMimeType);
mimeTypesGroup.add(mimeTypePredicate);
}
allowedTypeGroup.add(mimeTypesGroup);
}
allowedTypesGroup.add(allowedTypeGroup);
}
}
mainGroup.add(allowedPathsGroup);
mainGroup.add(allowedTypesGroup);
log.info("mainGroup final init = " + allowedTypesGroup);
Query query = builder.createQuery(mainGroup, session);
query.setStart(offset);
if (hitsPerPage > 0) {
query.setHitsPerPage(hitsPerPage);
} else {
query.setHitsPerPage(config.getPageSize());
}
log.info("Query: " + query.getPredicates().toString());
SearchResult result = query.getResult();
return result;
} catch (Exception e) {
log.error("Error occurred ", e);
}
return null;
}
Views
Replies
Total Likes
Hi,
Its look like you are trying to do full text search under some path(with excluded resource type)within cq:Page or dam:Asset.
Could you try with nt:base or/and nt:unstructured type because page content is not saved only cq:PageContent but nt:unstructured node also.
Could you please correct me if I am wrong and let me know in short what you are trying to do with this query?
Views
Replies
Total Likes
I figured out what was wrong. I'm doing a fulltext search (the name says it all), so if searching for a phrase like bank fees, the seach returns all pages with bank and fees. The only other option is to put quotes on 'bank fees', the problem with this approach is that the search returns pages with the exact phrase but pages with 'bank fee' are omitted because they don't match the search phrase. Is there any way of working around this? The Xpath query generated is below: Is it possible to create an Xpath query using Predicates that uses jcr:like instead of jcr:contains?
[
(jcr:contains(., '"bank fees"' ))
and (((@jcr:primaryType = 'cq:Page' ))
or ((@jcr:primaryType = 'dam:Asset' )
and (jcr:content/metadata/@dc:format = 'application/pdf' )))
]
Views
Replies
Total Likes
Hi,
Try with SQL2
select * from [nt:base] as s where isdescendantnode([/content]) AND s.[*] LIKE '%bank fee%' AND (s.[jcr:primaryType] = 'cq:Page' OR (s.[jcr:primaryType] = 'dam:Asset' AND s.[jcr:content/metadata/dc:format] = 'application/pdf' ))
Views
Replies
Total Likes
Unfortunately I need to use QueryBuilder to generate SQL2. My problem is what syntax to use for querybuilder
Views
Replies
Total Likes
Hello jamesm77050123
Any further tweaks to the query itself might now be scalable, or efficient. For example, using jcr:like will impact your performance, and I think the only tweak you can make being at query level is something like
"Sorry we didn't find any results for your searched term.
You can try changing the scope of the search term by adding an asterisk, such as bank* fee*, or wrapping your search in quotes and try again."
And a better alternative would be to try exploring the advanced search options for an index itself. For example, there are synonyms available for an index where what you basically have to do is figure out the index used by your query, and add an analyzer to your index with something called "Synonyms". In essence, you create a file, list some possible synonyms for your commonly searched terms and the index will now analyze any available synomyms for the search term input by the user.
It's true that this will be some manual work but considering your business and commonly used search terms, you can start this file with a few common words. You can read about this in Jackrabbit Oak – Lucene Index and look for the word "Synonym".
While the Synonyms is some manual work, Suggestions and Spellcheck in the index are also available. You can take a look at the link Jackrabbit Oak – Lucene Index for further insight into this.
Some detailed explanation is also listed in https://aemcorner.com/search-in-aem/
I hope this helps.
Best Regards,
Aneet Arora
Views
Replies
Total Likes
Hi,
In QueryBuilder there is no like operation for full text search.
If you know the properties for value then you can use like operation
e.g.
path=/content
1_property=sling:resourceType
1_property.value=foundation/components/text
1_property.operation=like
orderby=path
Views
Replies
Total Likes
Thanks for the answers. Unfortunately I can't implement an index without management support and bureaucracy and stepping on other peoples toes (company politics)
What I'm wondering, if there a performance difference if i create a JCR_SQL2 query instead of using query builder? Something like
select = SELECT * FROM [jcr:content] AS s WHERE CONTAINS(s.*, '"my/search-expression"') AND s.* LIKE '%my/search-expression%';
//some code
Query query = queryManager.createQuery(select, Query.JCR_SQL2);
Views
Replies
Total Likes