Direct Integration

Requirements

  • Java version >=1.8
  • around 100MB to 500MB additional Java Heapspace (depending on the amount of data to be managed by the service)
  • If using a firewall, please adjust the configuration to allow connections to the following HTTPS Endpoints https://query.searchhub.io/ and https://import.searchhub.io/

Maven Dependency

The basic SmartSuggest library is part of the Open-Commerce-Search stack. In order to load the search|hub data, our searchhub-suggest-data-provider must be added to the classpath. All related components can be pulled as a maven dependency from our repository https://nexus.commerce-experts.com/content/repositories/searchhub-external/

<dependency>
    <groupId>de.cxp.ocs</groupId>
    <artifactId>smartsuggest-lib</artifactId>
    <version>0.1.1</version>
</dependency>
<dependency>
    <groupId>io.searchhub</groupId>
    <artifactId>searchhub-suggest-data-provider</artifactId>
    <version>0.7</version>
</dependency>

<!-- ... -->

<repository>
    <id>external-releases</id>
    <url>https://nexus.commerce-experts.com/content/repositories/searchhub-external/</url>
</repository>

Essential Usage

The QuerySuggester is the central object of the smartsuggest library. It is used to fetch the matching suggestions based on the (partial) user input. To get access to a QuerySuggester object, a single QuerySuggestManager must be built and maintained as a central reference. This is important as the QuerySuggestManager instance takes care of updating the suggest data should the data change. It can also be used to shutdown any QuerySuggesters and therefore free related resources.

A QuerySuggester isntance can be accessed from the QuerySuggestManager using an “index name” as a parameter. The index name is the full tenant name used at search|hub. For example: “myshop.com”.

To load the correct data, the update process must get your search|hub API key, which you will receive during search|hub onboarding. This API key must be set either, as environment variable “SH_API_KEY” or, as system property “searchhub.apikey” within the Java environment.

Usage Example

static QuerySuggestManager qsm;
static {
  try
    // this should not be necessary, instead the API key should be set from
    // the outside of the java process
    System.setProperty("searchhub.apikey", "123abc");

    qsm = QuerySuggestManager.builder()
          // required for lucene where it puts the index files
          .indexFolder(Files.createTempDirectory("smartsuggest"))
          // the builder also has other options
          .build();
  }
  catch (IOException e) {
    throw new UncheckedIOException(e);
  }
}

// It's recommended to bind the querySuggestManager instance to your JVM's lifecycle
// and close the QueryMapperManager during shutdown.
// Internally a ScheduledExecutorService is used, that will be stopped then.
@PreDestroy
public void onJvmShutdown() {
    querySuggestManager.close();
}

private List<String> suggestQueries(String userQuery, int maxSuggestions) throws IOException {
  // Suggestions are grouped by their match-type per default
  List<Result> groupedSuggestions = qsm.getQuerySuggester("example.com")
      .suggest(userQuery, maxSuggestions, Collections.emptySet());

  if (groupedSuggestions.isEmpty()) return Collections.emptyList();

  // this is how the grouped suggestions could be transformed into a simple string list
  List<String> simpleSuggestions = new ArrayList<>(maxSuggestions);

  for (Result suggestGroup : groupedSuggestions) {
    if ((simpleSuggestions.size() + suggestGroup.getSuggestions().size()) > maxSuggestions) {
      for (String s : suggestGroup.getSuggestions()) {
        simpleSuggestions.add(s);
        if (simpleSuggestions.size() == maxSuggestions) break;
      }
    }
    else {
      simpleSuggestions.addAll(suggestGroup.getSuggestions());
    }

    if (simpleSuggestions.size() == maxSuggestions) break;
  }

  return simpleSuggestions;
}

The javadoc of the QuerySuggestManager.builder() methods tell you more about the available settings.

Monitoring

SmartSuggest, optionally, provides internal metrics using the Micrometer framework. If you’d like to tap into those metrics, simply add the necessary Micrometer connector to your dependencies followed by, your desired MeterRegistry.

 // ...
 MeterRegistry meterRegistry = getYourMeterRegistryInstance();

 // example: to reveal metrics over JMX create a JmxMeterRegistry
 meterRegistry = new JmxMeterRegistry(JmxConfig.DEFAULT, Clock.SYSTEM);

 // and add it to the QueryMapperManager.builder afterwards
QuerySuggestManager.builder()
   // ...
   .addMetricsRegistryAdapter(MeterRegistryAdapter.of(meterRegistry));
   // ...

You will be able to track the following metrics:

smartsuggest.update.success.count.total
Total number of successful data updates per tenant. This metric is tagged with the corresponding tenant_name and tenant_channel.
smartsuggest.update.fail.count
Number of successive failed update attempts for a certain tenant. If an update succeeds, this value will be reset to “0”. If this value reaches “5”, the respective update process will be stopped and only restarted, if suggestions for the related tenant are requested again. This metric is tagged with the corresponding tenant_name and tenant_channel.
smartsuggest.suggestions.size
Current number of raw suggestion records per tenant. This metric is tagged with the corresponding tenant_name and tenant_channel.
smartsuggest.suggestions.age.seconds
That is the amount of time passed, since the last successful update took place. This metric is tagged with the corresponding tenant_name and tenant_channel.