Skip to content

POST /direct-browse

904Labs A.I. for Search optimizes the item listing for a category: once you send a category to A.I. for Search's browse endpoint, it will return a JSON response with an optimized product listing.

Request

HTTP request

POST https://api.904labs.com/sls/{customer_id}/direct-browse?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
api_key string (required) Your API key.
session_id string (required) The session ID for the user browsing.
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 browse (e.g., age group, subshop). (Default: default)
skip_sls boolean (optional) Indicates whether or not to apply our trained ranking functions for this request. Used in combination with the sort parameter. When set to true, items in the category are sorted purely by the sort parameter. When set to false, the first 100 items are ranked by our system and the remaining items in the category are sorted by the sort parameter. (Default: false)

Request body

Property name Value Description
filters json (required) Filters for selecting items in your categories. Filters that refer to facets have a _name, which is identical to the facet name and is used to generate correct facet counts in aggs.
sort json (required) Sort order that you use for your category. See skip_sls above for details. Eligable fields should have be defined in the documents at indexing time (see Cloud Indexing schema)
size int (optional) Number of items per category page. (Default: 10)
from int (optional) Start category page. (Default: 0)

Example requests

Consider a user who browses the "chairs" category. To receive an optimized product listing for this category, you send the category as an Elasticsearch filter query in filters and the sorting parameter (as sort) to the endpoint. Below, we show an example where products are returned for the "chairs" category, and specifically red chairs, which are sorted by price (before optimization). We want to get the top 10 results.

import requests as r

headers = {"content-type": "application/json"}
URL_BROWSE = "https://api.904labs.com/sls/CUSTOMER_ID/direct-browse"
params = {
    "session_id": "SESSION_ID",
    "user_id": "USER_ID",
    "domain": "default",
    "locale": "en_US",
    "api_key": "APIKEY"
}
payload = {
    "sort": "number_sort.price",
    "filters": [ {
        "term": {
            "category.direct_parents": "chairs"
        }
    } , {
        "nested": {
            "_name": "color",
            "path": "search_data.string_facet",
            "filter": {
                "bool": {
                    "must": [ {
                        "term": {
                            "search_data.string_facet.facet-name": "color"
                        }
                    },
                    {
                        "term": {
                            "search_data.string_facet.facet-value": "red"
                        }
                    } ]
                }
            }
        }
    } ],
    "size": 10,
    "from": 0
}

response = r.post(URL_BROWSE, 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 items for this category.
results list List of items, the schema follows that of the Cloud Indexing schema.
aggs dict Aggregations over facets, can be used for filtering the results. 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 items.
sls_on boolean Flag indicating whether A.I. for Search ran successfully (true) or not (false).
timestamp int Current timestamp.

904Labs A.I. for Search returns a ranked list of a number (hits) of items in the category (the results). In addition to these results, the response contains a search_id. This search_id is used for sending feedback when users interact with the items so that A.I. for Search knows to which request 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": "color",
              "string_facets_facet_values": {
                "buckets": [
                  {
                    "key": "red",
                    "doc_count": 101
                  },
                  {
                    "key": "blue",
                    "doc_count": 210
                  },
                  {
                    "key": "orange",
                    "doc_count": 2
                  }
                ]
              }
            }
          ]
        }
      }
    }
  }, 
  "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": "color", 
              "facet-value": "red"
            }, 
            {
              "facet-name": "model", 
              "facet-value": "desk chair"
            },
            {
              "facet-name": "weight", 
              "facet-value": "42kg"
            }
          ]
        }
      ], 
      "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 model and color are applied, counts of all other facets should take these two filters into account. However, the counts for model should only filter on color, and those for color should only filter on model (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.

{
  "color": {
    "red": 101,
    "blue": 210,
    "orange": 2
  },
  "model": {
    "desk chair": 500,
    "lounge chair": 45
  }
}