Tuesday, July 14, 2020

How to enable Did you mean feature in Adobe Search and Promote | Enable Guided Suggestions in Adobe Search and Promote

This tutorial explains the details on “Did You Mean” feature in Adobe Search and Promote.

You can configure “Did You Mean” so that customers are given suggestions for valid search terms when they have tried searches that have failed. Suggestions are formed by looking for spelling and typing corrections to the search terms that result in a valid search.

This feature helps to avoid the null search due to wrong spelling of words in the search term and improve the conversion.

Configuring Did You Mean

You can tailor how site search/merchandising makes search suggestions when a customer’s query returns no, or minimal, search results.

To enable Did You Mean feature, access Linguistics → Did You Mean

adobe-search-and-promote-did-you-mean

Remove these Words from Suggestions — enter space or line separated words to filter undesirable suggestions.

Suggestion Algorithm — Adjusts how far the software goes to find suggestions. If a user makes a one-letter mistake, all of the algorithms come up with the same suggestions. The reason why is because it only takes one edit to arrive at a working suggestion, and all algorithms find words that are close to the original. But when the original search terms are not similar to existing terms in the index, the Deep and Bad Spellers Suggestion Algorithms continue to search for possible suggestions. This scenario is useful if a customer tries a proper name that is hard to type, and they sound out the names. However, if you only want similar suggestions to appear, you can choose the Quick algorithm

Default count of suggestions to show — Specifies the number of Did You Mean term suggestions (0–20) that you want to show when a customer’s search returns no results. The default is 3.

Minimal suggestion word length — Prunes Did You Mean terms by specifying the minimal number of letters for a suggested word. For example, if you set the value to 4, the software does not suggest a word that is 1, 2, or 3 characters long. If you specify a value of 0, no short words are removed from the term suggestions. If you specify a high value, it usually results in no term suggestions. The default value is 3.

Minimum index frequency — Specifies the minimum number of times a word has to appear in the index before it is included in the Did You Mean dictionary. You cannot specify a negative number in the field.

Search for suggest term if no results — Automatically re-searches for the first suggested term when a customer’s search yields no results and there is at least one Did You Mean term suggestion.

Make suggestions due to low results — If a customer searches for a term that yields less than ten results, the search engine checks to see if it has a suggestion that can yield more than 100 results. The number of suggestions is controlled by the value that is specified in Default count of suggestions to show. The low and high threshold are configurable by the options below.

Make suggestions when the initial results are fewer than — Controls the number of results when the system starts to offer suggestions. This option appears only when you check Make suggestions due to low results. The default is 10.

The Did You Mean functionality can be enabled in three ways: make suggestions due to no results, automatically search against the first suggestion when we have no results, or make suggestions due to low results (where the suggestions have a higher result count).

Let us enable the indexing with IndexConnector(the URL entrypoint can be used if required), refer the below URL for details on enabling IndexConnector and configuring custom templates.

The sample feed data for indexing, enable the required metadata, IndexConnector, URL entrypoint and the custom templates by following the previous tutorial URL

<feed xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
<channel>
<title>Product Feed</title>
<Item>
<link>https://qa.example.com/product-title/p/prod1</link>
<title>
<![CDATA[Java Title]]>
</title>
<description>
<![CDATA[<p>Prod1 description</p>]]>
</description>
<productType>Java</productType>
<ProductId>prod1</ProductId>
<imageUrl>/content/dam/Images/product/prod1.jpg</imageUrl>
</Item>
<Item>
<link>https://qa.example.com/product-title/p/prod2</link>
<title>
<![CDATA[Lava Title]]>
</title>
<description>
<![CDATA[<p>Prod2 description</p>]]>
</description>
<productType>Lava</productType>
<ProductId>prod2</ProductId>
<imageUrl>/content/dam/Images/product/prod2.jpg</imageUrl>
</Item>

</channel>
</feed>

Enable the transport template — custom_backend_json.tpl

<search-content-type-header charset="UTF-8">
{
"general": {
"query" : "<search-query />",
"total" : "<search-total />",
"lower" : "<search-lower />",
"upper" : "<search-upper />"
},
<search-if-suggestions>
"suggestions":
[
<search-suggestions>
{
"suggestion":"<search-suggestion-text />",
"count": "<search-suggestion-result-count>"
}<search-if-not-last-suggestion>,</search-if-not-last-suggestion>
</search-suggestions>
],
</search-if-suggestions>


"facets" : [
{
"name" : "n1",
"values" : [<search-field-value-list name="n1" quotes="yes" data="values" sortby="values" encoding="json" />],
"counts" : [<search-field-value-list name="n1" quotes="no" data="results" sortby="values" />]
}
],
"results" : [
<search-results>
{
"fields" :
[
{
"name" : "mdi",
"value" : "<search-display-field name="mdi" length="500" encoding="json" />"
},
{
"name" : "title",
"value" : "<search-display-field name="title" encoding="json" />"
},
{
"name" : "productType",
"value" : "<search-display-field name="productType" encoding="json" />"
}
]
}
<search-if-not-last>,</search-if-not-last>
</search-results>
]
}

Enable the transport template — custom_presentation_json.tmpl

<guided-content-type-header content="application/json" />
<guided-if-query-param-defined gsname="callback" /><guided-query-param gsname="callback" />(</guided-if-query-param-defined>
{
"general" :
{
"query" : "<guided-query-param gsname='q' />",
"total" : "<guided-results-total />",
"page_lower" : "<guided-results-lower>",
"page_upper" : "<guided-results-upper>",
"page_total": "<guided-page-total/>"
},

"suggestions":
{
"auto_searched": "<guided-if-suggestion-autosearch>1<guided-else-suggestion-autosearch>0</guided-if-suggestion-autosearch>"
<guided-if-suggestion-autosearch>,
"auto_search_query":"<guided-query-param gsname="q"/>",
"original_query":"<guided-suggestion-original-query />"
</guided-if-suggestion-autosearch>,
"suggestion_low_result":"<guided-if-suggestion-low-results>1<guided-else-suggestion-low-results>0</guided-if-suggestion-low-results>",
"suggestion_items":[
<guided-if-suggestions>
<guided-suggestions>
{
"path": "<guided-suggestion-path>",
"value": "<guided-suggestion>",
"count": "<guided-suggestion-result-count>"
}<guided-if-not-last>,</guided-if-not-last>
</guided-suggestions>
</guided-if-suggestions>
]
},"facets" :
[

],
"results" :
[
<guided-results gsname="default">
{
"index" : "<guided-result-index />",
"title" : "<guided-result-field gsname="title" escape="ijson" />",
"productType" : "<guided-result-field gsname="productType" escape="ijson" />"
}<guided-if-not-last>,</guided-if-not-last>
</guided-results>
]
}
<guided-if-query-param-defined gsname="callback">)</guided-if-query-param-defined>

The configurations are ready, let us now run a Stage indexing (note the configuration are not pushed to live yet)

Index →Full Index →Staged Index →Run Full Index

Image for post

Let us now test with the default “Did You Mean” configurations

Access http://stage-xxxxxxxxxxx.guided.ss-omtrdc.net/do=json&sp_staged=1&q=bava

xxxxxxxxxxx — Search and Promote account number

There is no matching data for the term “bava”, this will provide all the available suggestions with search link and search value those data can be used to show the suggestion to the users.

{
"general": {
"query": "bava",
"total": "0",
"page_lower": "0",
"page_upper": "0",
"page_total": "1"
},
"suggestions": {
"auto_searched": "0",
"suggestion_low_result": "0",
"suggestion_items": [
{
"path": "?do=json;i=1;q=lava;sp_staged=1",
"value": "lava",
"count": "1"
},
{
"path": "?do=json;i=1;q=java;sp_staged=1",
"value": "java",
"count": "1"
}
]

},
"facets": [],
"results": []
}

Let us now enable “Search for suggest term if no results” option — Automatically re-searches for the first suggested term when a customer’s search yields no results and there is at least one Did You Mean term suggestion.

Image for post

Access http://stage-xxxxxxxxxxx.guided.ss-omtrdc.net/do=json&sp_staged=1&q=bava, this will provide all the available suggestions(other than the first suggestion used for auto search) and returns the result by searching with first suggested term.

{
"general": {
"query": "lava",
"total": "1",
"page_lower": "1",
"page_upper": "1",
"page_total": "1"
},
"suggestions": {
"auto_searched": "1",
"auto_search_query": "lava",
"original_query": "bava",
"suggestion_low_result": "0",
"suggestion_items": [
{
"path": "?do=json;i=1;q=java;sp_staged=1",
"value": "java",
"count": "1"
}
]

},
"facets": [],
"results": [
{
"index": "",
"title": "Lava Title",
"productType": "Lava"
}
]

}

“Make suggestions due to low results” — if a customer searches for a term that yields less than ten results, the search engine checks to see if it has a suggestion that can yield more than 100 results.

Image for post

This will return “suggestion_low_result”: “1” and the available suggestions that yield more than 100 results but somehow the scenario is not working as expected. I will be updating the tutorial with further details.

The configuration can be pushed live after successful validation and run a live index →Full Index →Live Index →Run Full Index

The URL to access live data http://xxxxxxxxxxx.guided.ss-omtrdc.net/do=json&q=bava

The suggest data returned can be used to enable the “Did You Mean” functionality in the website.



Monday, March 12, 2018

Exception in thread "main" java.lang.NoSuchMethodError: org.slf4j.helpers.MessageFormatter.format(Ljava/lang/String;Ljava/lang/Object;)Lorg/slf4j/helpers/FormattingTuple;Jcr2davRepositoryFactory

I was getting the below exception while connecting to AEM JCR repository through Java API(JCR webdav) using Jcr2davRepositoryFactory.

Exception in thread "main" java.lang.NoSuchMethodError: org.slf4j.helpers.MessageFormatter.format(Ljava/lang/String;Ljava/lang/Object;)Lorg/slf4j/helpers/FormattingTuple;
at org.slf4j.impl.Log4jLoggerAdapter.debug(Log4jLoggerAdapter.java:229)
at org.apache.jackrabbit.jcr2spi.Jcr2spiRepositoryFactory$RepositoryConfigImpl.getCacheBehaviour(Jcr2spiRepositoryFactory.java:272)
at org.apache.jackrabbit.jcr2spi.Jcr2spiRepositoryFactory$RepositoryConfigImpl.<init>(Jcr2spiRepositoryFactory.java:229)
at org.apache.jackrabbit.jcr2dav.Jcr2davRepositoryFactory.getRepository(Jcr2davRepositoryFactory.java:104)
at org.apache.jackrabbit.jcr2dav.Jcr2davRepositoryFactory.getRepository(Jcr2davRepositoryFactory.java:87)
at workarea.core.GetRepositorySize.main(GetRepositorySize.java:25)

To fix the issue add the slf4j-log4j12 with lower version and also exclude jcl-over-slf4j from jackrabbit-jcr2dav dependency.

<dependency>
<groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.5.0</version>
</dependency>
 
<!-- https://mvnrepository.com/artifact/org.apache.jackrabbit/jackrabbit-jcr2dav -->
<dependency>
    <groupId>org.apache.jackrabbit</groupId>
    <artifactId>jackrabbit-jcr2dav</artifactId>
    <version>2.17.1</version>
    <scope>provided</scope>
    <exclusions>     
        <exclusion>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        </exclusion>
    </exclusions>
</dependency>



Friday, November 24, 2017

Rewrite Rules with PT(Pass Through) Flag is not working in AEM Dispatchers - Adobe Experience Manager(AEM)

Rewrite Rules with PT(Pass Through) Flag is not working in AEM Dispatchers - Adobe Experience Manager(AEM)

How to define SEO/User friendly URL's in Adobe Experience Manager(AEM)


The Rewrite Rules with PT Flag helps us to define the SEO/User friendly URL's by hiding the internal URL's.

Let consider a scenario - The product URL should be rewritten to SEO/User friendly URL.

The internal product URL is - /en/test/pdp/book.html?id=123, this URL is not SEO/User friendly as the title of the the product is not part of the URL

The URL should be rewritten to /en/test/Sample_Book/book/pdp.html?id=123 internally without changing the Browser URL

Rewrite_Rule_with_PT_flag



Wednesday, July 5, 2017

Exposing the AEM resources through OAuth - Adobe Experience Manager(AEM)

Exposing the AEM resources through OAuth - Adobe Experience Manager(AEM)

This post will explain the approach to expose the resources through OAuth in Adobe Experience Manager(AEM).

Refer https://www.albinsblog.com/2017/05/how-to-get-basic-profile-details-of-user-through-oauth.html for the basic configurations to expose the the resources thorough OAuth.

Exposing /etc/designs/geometrixx/static.css through OAuth

Configure the "Allowed Scope" as "/etc/designs/geometrixx"(based on the resource that should be exposed) in "Adobe Granite OAuth Resource Server"


The OAuth Authentication handler is not enabled by default and it looks to be an product defect.




Monday, May 29, 2017

How to expose Regex based rest service in Adobe Experience Manager( AEM)

How to expose Regex based rest service in Adobe Experience Manager(AEM)

This post will explain the approach to expose the regex based rest service in Adobe Experience Manager(AEM). By default OSGI will not support exposing regex based rest services and it will only support the services based on the specified Path or Resource Type.

Install OSGI JAX-RS connector:

Install(/system/console/bundles) jersey-all, publisher, provider-security and other required bundles e.g. provider-gson for JSON support and make sure the bundles are in Active state.

The bundles(jar) can be downloaded from following URL - http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.eclipsesource.jaxrs%22

com.eclipsesource.jaxrs-bundles

Develop the Servlet with required path mapping:

>=AEM 6.2

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

import org.osgi.service.component.annotations.Component;

@Component(service = RegexServlet.class)
@Path("/{catagroy}/{title}/p/{code : \\d{5}}")
public class RegexServlet {

  @GET
  @Produces({MediaType.TEXT_PLAIN})
  public String getProductDetails(@Context HttpServletRequest request, @Context HttpServletResponse response,@PathParam("catagroy") String catagroy,@PathParam("title") String title,@PathParam("code") String code) {

    return "code="+code+";catagroy="+catagroy+";title="+title;

    }
}

< AEM 6.2

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import javax.ws.rs.Path;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Service(RegexServlet.class)
@Component(metatype = false)
@Path("/{catagroy}/{title}/p/{code : \\d{5}}")
public class RegexServlet {

 @GET
 @Produces({MediaType.TEXT_PLAIN})
public String getProductDetails(@Context HttpServletRequest request, @Context HttpServletResponse response,@PathParam("catagroy") String catagroy,@PathParam("title") String title,@PathParam("code") String code) {

   return "code="+code+";catagroy="+catagroy+";title="+title;

    }
}

Add the following dependency in POM.xml

<dependency>
    <groupId>javax.ws.rs</groupId>
    <artifactId>javax.ws.rs-api</artifactId>
    <version>2.0</version>
</dependency>

Install the package and make sure the core bundle status is active.

Verify whether the RegexServlet service is registered in system console

JAX-RS_Servlet

The servlet will accept the request with matching pattern - the servlet path should be starting with /services

The Path Regex pattern specified in the servlet will match for the following URL  - localhost:4502/services/categoryTest/Sampletitle/p/12345 (Code should be 5 digit)

Download the sample code -https://gitlab.com/albinsblog-data/RegexServlet/tree/master (Refer com.regex.servlet.core.RegexServlet.java in core module)
The sample code is tested in AEM 6.3 but it should be working in 6.2