Search

This section covers the details of how to implement search functionality on your site using Loop54.

To begin with, you need to have your API access set up.

If you want to see the documentation for the underlying API calls for search, you find them in our API reference.

Loop54 Search Results

The search results from Loop54 are returned in two lists; Results and RelatedResults. Products in the Results list contain the actual direct hits to the user query. Products in the RelatedResults list are products that are contextually similar to the user intent. The RelatedResults list will pick up on synonym products that are not direct hits put related to the users area of interest.

The two lists Results and RelatedResults need to be presented to the user and the best way will vary from implementation to implementation, consult your Customer Success Manager for advice if you are unsure.

Search Parameter Introduction

The search term is simply called the query.

query : the actual query as entered by the user

Paging is implemented using parameters skip and take. Imagine these as operating on a hypothetical search result of a certain length. The take parameter specifies the length of the response returned by the function-call and the skip parameter specifies from where the response starts reading from the result. Both take and skip parameters are applied to Results and RelatedResults independently.

Example
skip  : the number of items in the total result to skip 
take  : the maximum length of the returned response

skip = 20
take = 10
query = "user provided query"

'''This call will return results 21-30'''
results = search(query, skip, take)

Search and Render Results

The number of returned results and related results will be between 0 and what you specified for take. You check it by reading the length of the returned results array.

// The search field
//initialize "Search" request and set search query
SearchRequest request = new SearchRequest(query);

//specify number of response items
request.ResultsOptions.Skip = 0;
request.ResultsOptions.Take = 10;
request.RelatedResultsOptions.Skip = 0;
request.RelatedResultsOptions.Take = 9;

//fetch response from engine
SearchResponse response = _loop54Client.Search(request);

// INJECT SAMPLE search-check-results BEGIN
CheckResults(response);
// INJECT SAMPLE END

//render direct results
var results = response.Results.Items;
if (!results.Any())
    Debug.WriteLine("There were no items matching your search.");

foreach (var resultItem in results)
{
    var productId = resultItem.Id;
    var productTitle = resultItem.GetAttributeValueOrDefault<string>("Title");
    Debug.WriteLine(productId + " " + productTitle); //render a product on the search results page
}

//render related results
var relatedResults = response.RelatedResults.Items;
if (relatedResults.Any())
    Debug.WriteLine("Maybe you also want these?");

foreach (var resultItem in relatedResults)
{
    var productId = resultItem.Id;
    var productTitle = resultItem.GetAttributeValueOrDefault<string>("Title");
    Debug.WriteLine(productId + " " + productTitle); //render a product on the search results page
}
C# source code on Github: SearchController.cs
// The search field
// initialize "Search" request and set search query
SearchRequest request = new SearchRequest(query);

// specify the number of response items
request.resultsOptions.skip = 0;
request.resultsOptions.take = 10;
request.relatedResultsOptions.skip = 0;
request.relatedResultsOptions.take = 9;

// fetch the response from the engine
SearchResponse response = loop54Client.search(request);

// INJECT SAMPLE search-check-results BEGIN
checkResults(response);
// INJECT SAMPLE END

// render direct results
List<Entity> results = response.results.items;

if (response.results.count == 0)
  System.out.println("There were no items.");

for(Entity resultItem : results)
{
  String productId = resultItem.id;
  String productTitle = resultItem.getAttributeValueOrNull("title", String.class);
  System.out.println(productId + " " + productTitle); //render a product on the search results page
}

// render recommended results
List<Entity> relatedResults = response.relatedResults.items;

if (response.relatedResults.count > 0)
  System.out.println("Maybe you also want these?");

for(Entity resultItem : relatedResults)
{
  String productId = resultItem.id;
  String productTitle = resultItem.getAttributeValueOrNull("title", String.class);
  System.out.println(productId + " " + productTitle); //render a product on the search results page
}
Java source code on Github: SearchController.java
// The search field
// initialize "Search" request and set search query

//specify number of response items
var options = {
  skip: 0,
  take:10,
  relatedResultOptions: {
    skip:0,
    take:9
  }
};

//fetch response from engine
var response = client.search(query, options); 
response = response.then((r) => {
    var data = r.data;
    // INJECT SAMPLE search-check-results BEGIN
    checkResults(data);
    // INJECT SAMPLE END
    
    //render direct results
    var results = data["results"].items;
    if (!results || results.length == 0)
    {
      console.log("There were no items matching your search.");
    }
    else
    {
      console.log("Total number of items: " + data["results"].count);
      for (var i in results)
      {
        var productId = results[i].id;
        var productTitle = results[i].attributes ? results[i].attributes.find(function(a){return a.name=="Title"}).values[0] : "";
        console.log(productId + " " + productTitle); //render a product on the search results page
      }
    }

    //render recommended results
    var relatedResults = data["relatedResults"].items;
    if (relatedResults && relatedResults.length > 0)
    {
      console.log("Maybe you also want these?");
      console.log("Total number of related results: " + data["relatedResults"].count);
      for (var i in relatedResults)
      {
        var productId = relatedResults[i].id;
        var productTitle = relatedResults[i].attributes ? relatedResults[i].attributes.find(function(a){return a.name=="Title"}).values[0] : "";
        console.log(productId + " " + productTitle); //render a product on the search results page
      }
    }
  }
);
JavaScript source code on Github: search.js
$request = $connector->search('meat');
$request->resultsOptions()
    ->sortBy(
        \Loop54\API\ResultsOptions::TYPE_ATTRIBUTE,
        \Loop54\API\ResultsOptions::ORDER_ASC,
        'Name'
    )
    ->skip(3)
    ->take(2)
    ->addDistinctFacet(
        'Category',
        'Category2'
    );

/* Actually perform the search query */
$response = $connector->query($request);

// INJECT SAMPLE search-check-results BEGIN
checkSearchResponse($response);
// INJECT SAMPLE END

/* Get the total result count, which may help with pagination */
$count = $response->getRaw()->getResults()->getCount();
$current_count = sizeof($response->getResults());
echo 'Found in total ' . $count . ' results. '
    . 'Showing ' . $current_count . ':' . PHP_EOL;

/* Print all results in this response */
foreach ($response->getResults() as $entity) {
    $id = $entity->getId();
    $title = $entity->getAttribute('Title');
    echo $id . ': ' . $title . PHP_EOL;
}

/* Print all related results in this response */
echo PHP_EOL . 'You might also like these:' . PHP_EOL;
foreach ($response->getRelatedResults() as $entity) {
    $id = $entity->getId();
    $title = $entity->getAttribute('Title');
    echo $id . ': ' . $title . PHP_EOL;
}
PHP source code on Github: Simple.php

Check Engine Response

The engine returns a MakesSense value which indicates if the engine could find a reasonable match for the query in the product catalog. A False response means that the engine is not sure what the user meant and the result will be a guess. Best practice in this case is to inform the user somehow. The result may also contain spelling suggestions in which case it is recommended to show said suggestions to the user.

// Check the search results
//if the result does not make sense, show error message
//(note that there may still be results!)
if (!response.MakesSense)
    Debug.WriteLine("We did not understand your query.");

//render spelling suggestions
if (response.SpellingSuggestions.Count > 0)
{
    var queries = response.SpellingSuggestions.Items.Select(o => o.Query);
    var suggestions = string.Join(", ", queries);

    Debug.WriteLine("Did you mean: " + suggestions + "?");
}
C# source code on Github: SearchController.cs
// Check the search results
// if the result does not make sense, show error message
// (note that there may still be results!)
if (!response.makesSense)
  System.out.println("We did not understand your query.");

// render spelling suggestions
if (response.spellingSuggestions.count > 0)
{
  List<QueryResult> queryResults = response.spellingSuggestions.items;
  List<String> queries = queryResults.stream().map(q->q.query).collect(Collectors.toList());

  System.out.println("Did you mean: " + String.join(", ", queries) + "?");
}
Java source code on Github: SearchController.java
// Check the search results
// if the result does not make sense, show error message
// (note that there may still be results!)
if (!data["makesSense"])
  console.log("We did not understand your query.");

//render spelling suggestions
if (data["spellingSuggestions"] && data["spellingSuggestions"].count > 0)
{
  var queries = data["spellingSuggestions"].items.map(o => o.query);
  console.log("Did you mean: " + queries.join() + "?");
}
JavaScript source code on Github: search.js
if (!$response->getMakesSense()) {
    echo 'We did not understand your query' . PHP_EOL;
}
$spellingSuggestions = $response->getSpellingSuggestions();
if (!empty($spellingSuggestions)) {
    $queries = array_map(
        function ($suggestion) {
            return $suggestion->getQuery();
        },
        $spellingSuggestions
    );
    $suggestions = join(', ', $queries);
    echo 'Did you mean: ' . $suggestions . '?' . PHP_EOL;
}
PHP source code on Github: Simple.php