Skip to content

POST /direct-search

904Labs A.I. for Search takes care of query interpretation and result optimization: once you send a text query to A.I. for Search, it will return a JSON response with an optimized ranking of search results.

Request

HTTP request

POST https://api.904labs.com/sls/{customer_id}/direct-search?q={query}&session_id={session_id}&user_id={user_id}&domain={domain}&locale={locale}&api_key={api_key}

Request attributes

Attribute Type Description
customer_id string (required) Your customer ID

Request parameters

Parameter Type Description
q string (required) The suggestion from POST /suggestion or the original query. URL encoded.
api_key string (required) Your API key.
session_id string (required) The session ID for the user issuing the query.
locale string (required) Country and language of the shop/site in ll_TT format, where ll is the language in ISO 639-1 format and TT is the territory in ISO 3166 format (e.g., en_US).
user_id string (optional) The user ID to allow for personalization of results.
domain string (optional) A particular domain to narrow the search (e.g., age group, subshop). (Default: default)
lang string (deprecated) Replaced by locale

Request body

Property name Value Description
filters json (optional) Filters that you use for your search engine. Each filter has a _name, which is identical to the facet name and is used to generate correct facet counts in aggs.
sort json (optional) Sort order that you use for your search engine (default is to sort by relevance)
size int (optional) Number of search results per result page. (Default: 10)
from int (optional) Start result page. (Default: 0)

Example requests

import requests as r

headers = {"content-type": "application/json"}
URL_SEARCH = "https://api.904labs.com/sls/CUSTOMER_ID/direct-search"
params = {
  "q": "red carpet",
  "session_id": "SESSION_ID",
  "user_id": "USER_ID",
  "domain": "default",
  "locale": "en_US",
  "api_key": "APIKEY"
}

payload = {
  "filters": [ {
    "nested": {
      "_name": "material",
      "path": "search_data.string_facet",
      "filter": {
        "bool": {
          "must": [ {
            "term": {
              "search_data.string_facet.facet-name": "material"
            }
          },
          {
            "term": {
              "search_data.string_facet.facet-value": "polyester"
            }
          } ]
        }
      }
    }
  } ],
  "size": 10,
  "from": 0,
  "sort": [ {
    "search_result_data.productId": {
      "order": "asc"
    }
  } ]
}

response = r.post(URL_SEARCH, headers=headers, params=params, json=payload)

Response

{
  "hits": int, 
  "results": [
    {
      "id": string, 
      "type": string,
      "search_data": [ ... ], 
      "search_result_data": { ... },
      "number_sort": { ... },
      "string_sort": { ... },
      "category": { ... },
      "product_data": { ... }
    }
  ],
  "aggs": { ... },
  "search_id": string, 
  "sls_on": boolean,
  "timestamp": int
}
Property name Value Description
hits int Number of results for this query.
results list List of search results, the schema follows that of the Cloud Indexing schema.
aggs dict Aggregations over facets, can be used for faceted search and filtering. aggs contains counts for string_facets, number_facets, and separate counts for facets that are part of the filters input (identified by their _name).
search_id string Unique identifier for this set of search results.
sls_on boolean Flag indicating whether A.I. for Search ran successfully (true) or not (false).
timestamp integer Current timestamp.

904Labs A.I. for Search returns a ranked list of a number (hits) of search results. In addition to these search results, the response contains search_id. This search_id is used for sending feedback when users interact with the results so that A.I. for Search knows to which query the feedback belongs; see POST /feedback. The aggs property contains the result of the aggregations, which take into account the filters. More on how to parse the aggs at the bottom of this page.

Example response

{
  "aggs": {
    "string_facets_filters": {
      "string_facets_nested": {
        "string_facets_facet_name": {
          "buckets": [
            {
              "key": "Brand",
              "string_facets_facet_values": {
                "buckets": [
                  {
                    "key": "Apple",
                    "doc_count": 11
                  },
                  {
                    "key": "Microsoft",
                    "doc_count": 10
                  }
                ]
              }
            }
          ]
        }
      }
    }
  }, 
  "hits": 21, 
  "results": [
    {
      "id": "559", 
      "search_data": [
        {
          "full_text": "This is the product description. This is the product title. And the technical specifications.", 
          "full_text_boosted": "This is the product description. This is the product title.", 
          "product_fields": [
            {
              "field-name": "name", 
              "field-value": "This is the product title."
            }, 
            {
              "field-name": "description", 
              "field-value": "This is the product description."
            },
            {
              "field-name": "specs", 
              "field-value": "And the technical specifications."
            },
          ], 
          "string_facet": [
            {
              "facet-name": "brand", 
              "facet-value": "Apple"
            }, 
            {
              "facet-name": "model", 
              "facet-value": "Airbook"
            },
            {
              "facet-name": "color", 
              "facet-value": "red"
            }
          ]
        }
      ], 
      "search_result_data": {
        "base_price": 1500, 
        "final_price": 1349, 
        "name": "This is the product title", 
        "number_of_variants": 1, 
        "productId": "559"
      }, 
      "type": "product"
    }
  ], 
  "search_id": "default:-:en:-:cfe70a", 
  "sls_on": true
}

Parsing aggregations

Aggregations (or facet counts) have to take into account the filters that are requested. For example, when filters for both brand and size are applied, counts of all other facets should take these two filters into account. However, the counts for brand should only filter on size, and those for size should only filter on brand (if we would apply both filters to these facet counts, they would return only counts for the value on which was filtered, and all other values would be zero). This is why the aggs property contains not only a list of facet counts on which all filters are applied (number_facets_filter and string_facets_filter), but also separate entries for those facets that are present in filters.

To properly parse the aggs property, one can use the sample code below. The second part of the sample code ensures that the correct counts are used for facets that are in the filters.

aggs = response.json()['aggs']

# compile list of all facets and counts
for facet_type in ["number", "string"]:
  for facet_name in aggs[facet_type+'_facets_filter'][facet_type+'_facets_nested'][facet_type+'_facets_facet_name']['buckets']:
    facets[facet_name['key']] = {}
    for facet_value in facet_name[facet_type+'_facets_facet_value']['buckets']:
      facets[facet_name['key']][facet_value['key']] = facet_value['doc_count']
  aggs.pop(facet_type+"_facets_filter")

# override facet counts for selected facets
for agg in aggs:
  facets[agg] = {}
  for facet_value in aggs[agg]['nested']['facet_name']['buckets'][0]['facet_values']['buckets']:
    facets[agg][facet_value['key']] = facet_value['doc_count']

This code will return a dictionary consisting of facet names, and for each facet name a dictionary of facet values with counts.

{
  "brand": {
    "Microsoft": 10,
    "Apple": 11,
    "Samsung": 9
  },
  "size": {
    "XL": 100,
    "L": 45,
    "M": 121
  }
}