Query Configuration

Each Query can be configured to search your data in a variety of ways. Example use cases include, but are not limited to:

  • Searching for documents by only title or name;
  • Searching by unique identifier;
  • Searching by both name and description;
  • Configuring whether all user query words should match the document;
  • Adding predefined facets, filters, sorting and pagination settings.

Some of the following settings can be overridden with Public Query request.

Query Fields

Query fields are used to select in which document fields we should search for matches with a user query.

queryFields configuration is an object with key-value pairs, where key defines document property and value is used to boost the relevance of query matches in that particular field. You can add multiple properties, but at least one is always required.

{
  "queryFields": {
    "name": 5,
    "author": 2,
    "description": 1
  }
}

In the example above, documents query with matches in name field will appear higher that those with matches in author or description.

Fields in queryFields configuration must be defined in Index mapping and need to have text, keyword or text_keyword types, which means that it is not possible to query by numeric properties.

Query fields cannot be overridden in Public Query request.

How to configure query to perform search in just one field?

{
  "configuration": {
    "queryFields": {
      "title": 1
    }
  }
}

How to configure query to perform search in multiple fields while giving more relevance to the product title?

{
  "configuration": {
    "queryFields": {
      "title": 10,
      "description": 2
    }
  }
}

Select Fields

Select fields configuration setting (selectFields) allows you to control which properties from the document are returned with search query results.

Select fields is configured as an array of strings, where each element is a property in your document. Properties must be defined in Index mapping. selectFields must contain at least one item.

{
  "configuration": {
    "selectFields": ["id", "title"]
  }
}

The query, which has selectFields configured as in the example above, will only return selected properties when executed:

{
  "searchText": "television",
  "total": 4,
  "items": [
    { "id": 1, "title": "Samsung Television" },
    { "id": 2, "title": "LG Television" },
    { "id": 3, "title": "Television Set" },
    { "id": 4, "title": "Televisions" }
  ]
}

The less properties are returned, the better the performance of your query, as less data needs to be transferred through network.

Select fields cannot be overridden in Public Query request.

Pagination

You can use limit and offset parameters for your query results pagination:

{
  "searchText": "tv",
  "offset": 5,
  "limit": 10
}

Offset and limit, if set, will be returned with query results.

Limitations:

  • offset parameter should not exceed 1000000;

  • limit parameter should not exceed 1000.

If you prefer using page number and and page size as parameters, you can use this formula to obtain offset and limit:

limit = pageSize

offset = (pageNumber - 1) * pageSize

The example above assumes, that page numbering starts from 1.

Sorting

In query configuration, you can set default the sorting, using sort parameter:

{
  "searchText": "tv",
  "sort": [
    {
      "price": "asc"
    }
  ]
}

Sort configuration consists of array of sorting rules, with a sorting key (the name of your field, price in the example above), and sorting order (asc or desc).

Sorting by multiple parameters

You can pass multiple sorting parameters, if you need to sort by multiple fields at the same time:

{
  "searchText": "tv",
  "sort": [
    {
      "price": "asc"
    },
    {
      "in_stock": "desc"
    }
  ]
}

Sorting by relevance

If you still want to include LupaSearch relevance score in your results, you can use a special _relevance property. _relevance can only be sorted in desc order:

{
  "searchText": "tv",
  "sort": [
    {
      "in_stock": "desc"
    },
    {
      "_relevance": "desc"
    }
  ]
}

Sorting by click count

If you have integrated the Events API, LupaSearch internally tracks the number of clicks on each product. You can use special key _clickCount to sort your search results by popularity (number of clicks that each product has received):

{
  "searchText": "tv",
  "sort": [
    {
      "_clickCount": "desc"
    }
  ]
}

Sorting while retaining exact matches

In some cases it might be useful to retain exact matches at the top of the search results, even if they do not strictly follow the defined search rules.

For example, you might have a sorting rule that displays products out of stock at the bottom of the search results. However, if a user searches for a specific product that is out of stock, you might want to display it at the top of the search results, regardless of the sorting rule.

To achieve this, you can use a special _match property, which takes some additional configuration:

{
  "sort": [
    {
      "_match": "desc",
      "fields": ["code", "title"]
    },
    {
      "in_stock": "desc"
    },
    {
      "_relevance": "desc"
    }
  ]
}

The configuration above would always display exact matches in product code or title fields at the top of the search results, followed by in-stock products (ordered by relevance), and then the rest of the results sorted by relevance. Exact matches are case insensitive.

Sorting can be overridden with public queries.

Filters

In some cases matching results only by search text is not enough. Imagine that you want to list only results that matches your predefined criteria, e.g. you don't want to get matching products if they are not in stock. Or maybe you are preparing promotion page and you want to get only search results that have specific attributes values. For cases like these, you can use filtering by terms, range or hierarchy.

Filters can be set both in search query configuration and public search query. Filters configured in search query are automatically appended into each query by the same queryKey. If you want to provide additional filters dynamically, you can set filters in public query. If public query contains any filter in request, then configured search filters and filters provided in public query request are merged. Public filters can only contain fields that are presented in facet configuration. You can find more about public query filters in public query documentation.

Filters can be configured as object with key-value pairs, where key specifies document property defined in mapping and value contains set of values or properties depending on filter type. Filter value schema for each filter type is defined under related subsection below.

Filters object configuration example:

{
  "configuration": {
    "filters": {
      "tags": ["TV", "Electronics"],
      "price": {
        "gt": 10,
        "lte": 20
      },
      "categories": {
        "level": 1,
        "terms": ["Electronics"]
      }
    }
  }
}

Term Filters

Term filters are useful for exact keyword matching. To use term filters you need to specify document property defined in index mapping and array of string values. Multiple array values in the same filter property work as union.

Term filters configuration example:

{
  "configuration": {
    "filters": {
      "stock_status": ["IN_STOCK"],
      "tags": ["TV", "Electronics"]
    }
  }
}

This example can be translated to the following: return products that have stock_status equal to "IN_STOCK" and tags equal to ("TV" or "Electronics").

Range Filters

Range filters are useful for numeric range matching. Range filters can contain subset of provided comparison parameters:

  • gt - greater than.
  • gte - greater than or equal to.
  • lt - less than.
  • lte - less than or equal to.

All the mentioned parameters are optional, but you need to use at least one of them.

Range filters configuration example:

{
  "configuration": {
    "filters": {
      "price": {
        "gt": 10,
        "lte": 20
      },
      "rating": {
        "gte": 2,
        "lte": 4
      }
    }
  }
}

Hierarchy Filters

Hierarchy filter can be used on mapping property with the type of hierarchy.

Hierarchy filter configuration contains level and terms required keys.

  • level - non-negative integer that defines search depth of hierarchy field value. Base level is 0.
  • terms - array of string values that should match document attribute value in provided level.

For example, if you have multiple documents with attribute categories and value [Electronics > Cameras & Photo > Camera], you can filter all documents that are in subcategory "Camera". Filter configuration in this case looks like the following:

{
  "configuration": {
    "filters": {
      "categories": {
        "level": 2,
        "terms": ["Camera"]
      }
    }
  }
}

Existence filters

Existence filters are useful for filtering documents based on non-empty properties; specifically, those not equal to null or undefined. Notably, empty strings or boolean values set to false are not treated as empty in this context.

For example, if your documents have a brand property, you can filter documents that have a brand value by using the following filter:

{
  "configuration": {
    "filters": {
      "brand": {
        "exists": true
      }
    }
  }
}

The configuration above will exclude all documents that have an empty brand property. To perform the opposite, i.e. to only include documents with empty brands property, use Exclusion filters, as explained in the next section.

Logical condition filtering

In advanced use cases, you may want to create complex filters that rely on logical conditions, allowing you to combine multiple filters with _and and _or operators. These operators enable you to define multiple filtering rules that can be applied simultaneously, giving you fine-grained control over search results. This type of filtering is particularly useful when your search conditions require flexible combinations of criteria.

For example, you may want to retrieve products that meet one of several criteria, such as:

  • Products from a specific brand that are in stock.
  • Products from a specific category within a certain price range.

The following syntax illustrates the logical condition filtering structure:

{
  "_or": [
    {
      "_and": [{ "brand": ["Nike"] }, { "in_stock": [true] }]
    },
    {
      "_and": [{ "category": ["Sportswear"] }, { "price": { "lte": 50 } }]
    }
  ]
}

In SQL-like syntax, the given example can be expressed as follows: ((brand = 'Nike' AND in_stock = TRUE)) OR ((category = 'Sportswear' AND price <= 50))

Explanation of Logical condition operators:

  • _and: Requires all conditions within the array to be met. In the example, products from brand "Nike" that are also in stock will match this filter.
  • _or: Requires at least one condition within the array to be met. In the example, the results will include either products that match the first condition (brand "Nike" and in stock) or the second condition (in category "Sportswear" and price less than or equal to $50).

To ensure efficient processing, there is a maximum depth limit for nesting _and and _or conditions. Be cautious of overly complex filters as they may impact search performance and readability.

Exclusion filters

While filters help narrow down search results to match your predefined criteria, there might be cases where you want to explicitly exclude certain results from your search. This is where exclusion filters come in handy. They work in a similar manner to filters, but with the aim of removing certain entries from search results rather than including them.

For instance, you might want to exclude products that are out of stock, or you might be preparing a product list where certain items with specific attributes should not be included. To handle such requirements, you can apply exclusion filters by terms, range, or hierarchy.

Exclusion filters can be set both in the search query configuration and the public search query, similar to filters. The key difference is that exclusion filters remove matching results from the search output. If any exclusion filter is present in a request, then the configured search filters and the exclusion filters provided in the public query request are combined and used to filter out matching documents from the results.

The exclusion filters are configured as an object with key-value pairs, where the key specifies the document property defined in the mapping and the value contains a set of values or properties depending on the filter type. The filter value schema for each filter type is identical to their counterparts in the filters section.

Exclusion filters object configuration example:

{
  "configuration": {
    "exclusionFilters": {
      "tags": ["TV", "Electronics"],
      "price": {
        "gt": 10,
        "lte": 20
      },
      "categories": {
        "level": 1,
        "terms": ["Electronics"]
      }
    }
  }
}

Exclusion with existence filter

Existence filters can also be used in Exclusion filters. For example, if your documents have a brand property, you can exclude documents that have any brand value by using the following filter:

{
  "configuration": {
    "exclusionFilters": {
      "brand": {
        "exists": true
      }
    }
  }
}

The configuration above will return all documents that do not have any brand set (i.e. it is null or not defined).

Facets

When performing search, you only get the results that match search criteria. These results may have shared attribute values (e.g. books can have the same author, products can be assigned into the same category) and these values can be aggregated into the attribute collections (facets). Having such collections, you can see how many items of the search results fit into different collections and also perform filtering based on facet item values.

Facets in Lupa can be configured only on aggregable attributes such as keyword, text_keyword, hierarchy or numeric types.

Every facet has at least key, type, label attributes.

  • key attribute is the exact name of the data field.
  • type attribute defines what type should be applied for specified data field. Available data fields are terms, range, stats and hierarchy.
  • label attribute defines user-friendly name of the field. For example, attribute of stock_status can be named Stock status.

Facet attribute in search query configuration is an array of facet objects. Example:

{
  "configuration": {
    "facets": [
      {
        "key": "brand",
        "type": "terms",
        "label": "Brand",
        "limit": 15
      },
      {
        "key": "rating",
        "type": "range",
        "label": "Rating",
        "ranges": {
          "min": 1,
          "max": 5,
          "step": 1
        }
      },
      {
        "key": "price",
        "type": "stats",
        "label": "Price"
      },
      {
        "key": "category",
        "type": "hierarchy",
        "label": "Category",
        "maxDepth": 3,
        "limit": 50
      }
    ]
  }
}

Terms facets

Terms take specified field values and use each of them as separate item group which count parameter shows how many items has such attribute and value. If item has the same attribute with multiple values (e.g. "tags": ["fashion", "style", "outfit"]), then the same item is counted into each of tag group. You can change number of facet items in response by setting limit parameter in terms facet configuration. Default limit value is 100, maximum facet fields limit is 1000.

The terms facet result outputs all available values of a field, sorted by default in descending order based on the count of matching items. The sorting order can be customized using the order parameter, which supports the following options:

  • count_desc (default): Sorts terms by their count in descending order
  • key_desc - Sorts terms alphabetically in descending order
  • key_asc - Sorts terms alphabetically in ascending order
  • numeric_asc - Sorts terms based on the first numeric value in ascending order. In this sorting mode, numeric values are prioritized and displayed above any text values
  • numeric_desc - Sorts terms based on the first numeric value in descending order. Similar to numeric_asc, numeric values are displayed above text values.

The numeric sorting options (numeric_asc and numeric_desc) are particularly useful for fields with mixed numeric and string values, such as 1mm or 8 minutes. These options ensure that the terms are sorted in a numerically valid order, with numeric values taking precedence over text.

Configuration example of terms facet:

{
  "configuration": {
    "facets": [
      {
        "type": "terms",
        "key": "brand",
        "label": "Brand",
        "order": "count_desc",
        "limit": 3
      }
    ]
  }
}

Terms facet response contains the type, key, label parameters with the configured values. Additionally, there is items parameter which is an array of term objects with title and matching item count properties.

Response example of terms facet:

{
  "facets": [
    {
      "type": "terms",
      "key": "brand",
      "label": "Brand",
      "items": [
        {
          "title": "Dell",
          "count": 954
        },
        {
          "title": "Apple",
          "count": 741
        },
        {
          "title": "Asus",
          "count": 674
        }
      ]
    }
  ]
}

Range facets

Using terms facet type on numeric fields can be tricky, because numeric fields are more likely to have wider range of possible values (e.g. price can vary from 0.01 to thousands and more) and it would be inconvenient to list all available values. In this case we can use range facet type which allows you to check how many items matches provided range. Range term has range parameter which defines facet group boundaries. It can be configured by using intervals or step parameter.

Range intervals

Using range intervals you can configure custom intervals with unequal ranges. To define custom range intervals set ranges to be an array of objects where each object contains at least one (or both) from, to parameters. These parameters sets range boundaries. If you set object with only one of these parameters, the opposite boundary is set automatically to be minimum/maximum value of the field. Maximum number of intervals is 20.

Configuration example of range (interval) facet:

{
  "configuration": {
    "facets": [
      {
        "type": "range",
        "key": "size",
        "label": "Size",
        "ranges": [
          {
            "to": 10
          },
          {
            "from": 10,
            "to": 20
          },
          {
            "from": 20
          }
        ]
      }
    ]
  }
}

Response example of range (interval) facets:

{
  "facets": [
    {
      "type": "range",
      "key": "size",
      "label": "Size",
      "items": [
        {
          "title": "*-10.0",
          "count": 33,
          "to": 10
        },
        {
          "title": "10.0-20.0",
          "count": 27,
          "from": 10,
          "to": 20
        },
        {
          "title": "20.0-*",
          "count": 17,
          "from": 20
        }
      ]
    }
  ]
}

Range facet with step parameter

Using range facet with step parameter is useful if you need to configure range facet with equal intervals. To configure range facet to use interval configuration by step, set ranges parameter to be the object that contains min, max and step properties.

Configuration example of range (step) facet:

{
  "configuration": {
    "facets": [
      {
        "type": "range",
        "key": "rating",
        "label": "Rating",
        "ranges": {
          "min": 1,
          "max": 5,
          "step": 1
        }
      }
    ]
  }
}

Response example of range (step) facets:

{
  "facets": [
    {
      "type": "range",
      "key": "size",
      "label": "Size",
      "items": [
        {
          "title": "1.0-2.0",
          "count": 0,
          "from": 1,
          "to": 2
        },
        {
          "title": "2.0-3.0",
          "count": 5,
          "from": 2,
          "to": 3
        },
        {
          "title": "3.0-4.0",
          "count": 13,
          "from": 3,
          "to": 4
        },
        {
          "title": "4.0-5.0",
          "count": 95,
          "from": 4,
          "to": 5
        }
      ]
    }
  ]
}

Stats facets

Stats type facet is useful to get the minimum and maximum values for the specified field of search criteria matching results.

Configuration example of stats facet:

{
  "configuration": {
    "facets": [
      {
        "type": "stats",
        "key": "regular_price",
        "label": "Price"
      }
    ]
  }
}

Response example of stats facet:

{
  "facets": [
    {
      "type": "stats",
      "key": "regular_price",
      "label": "Price",
      "min": 1.59,
      "max": 99.99
    }
  ]
}

Hierarchy facets

Hierarchy type facet is useful if you have nested attribute structure. In this case you can set attribute type to hierarchy and construct attribute value in the following manner: [Parent > Child > Grandchild]. Hierarchy facet use ">" operator as nested structure separator, so each ">" in attribute's value defines additional level of that value.

Configuration of hierarchy facet consists of shared attribute parameters key, type, label, limit and additional maxDepth parameter which limits how deep nested structure can go.

Configuration example of hierarchy facet:

{
  "configuration": {
    "facets": [
      {
        "key": "category",
        "type": "hierarchy",
        "label": "Category",
        "maxDepth": 3,
        "limit": 50
      }
    ]
  }
}

Response example of hierarchy facet:

{
  "facets": [
    {
      "type": "hierarchy",
      "key": "category",
      "label": "Category",
      "level": 2,
      "currentName": "Cameras & Photo",
      "parentName": "Electronics",
      "parentKey": "Electronics",
      "items": [
        {
          "title": "Camera",
          "count": 20,
          "key": "Electronics > Cameras & Photo > Camera"
        },
        {
          "title": "Photo",
          "count": 2,
          "key": "Electronics > Cameras & Photo > Photo"
        }
      ]
    }
  ]
}

Dynamic facets

If you have a very large number of different facets (> 30 or 40) it's often not practical to display all of them to the users, even if certain search text values will filter out some of the empty ones. Moreover, an extremely large facet count can hurt search performance.

Dynamic facets can help you to automatically show only the most relevant facets to the user, based on current search results.

There are two types of dynamic facets: topItemsFilter and topItemsFilterWithCount.

Dynamic facets from top items

Dynamic facets from top items will look into your top search results and will find the most relevant facets based on the most frequent field values in top search results.

Example of dynamic facets from top items:

{
  "configuration": {
    "dynamicFacets": {
      "type": "topItemsFilter",
      "topItemsCount": 24,
      "limit": 15
    }
  }
}
  • type - dynamic facet type, should be set to topItemsFilter;
  • topItemsCount - number of top search results to analyze for dynamic facets;
  • limit - maximum number of dynamic facets to return.

Dynamic facets from top values of the selected field

Dynamic facets from top values of the selected field would find the best facets like this:

  1. Find the most frequent values of a selected field in your document (usually, categories), defined with facetKey
  2. For each top value, find the most frequent facet fields. For example, find the most frequent fields for each top category.
  3. Combine these facets and return up to limit number of them.
{
  "configuration": {
    "dynamicFacets": {
      "type": "facetTopValuesFilter",
      "facetKey": "category",
      "topValuesCount": 3,
      "limit": 15
    }
  }
}
  • type - dynamic facet type, should be set to facetTopValuesFilter;
  • facetKey - field name to find top values for;
  • topValuesCount - number of top values to find facets for;
  • limit - maximum number of dynamic facets to return.

Boosting

Boosting allows a slight reordering of the final query results by boosting products with bigger discount, higher number of reviews, or move specific brand products to the top of the search results page.

Lupa supports four types of boosting:

  • Phrase boosting (boost products with phrases that exactly match user's multi-word query);

  • Numeric boosting (boost results by numeric fields, like price, discount size, rating, popularity, ...);

  • Value boosting (boost by a text value: specific brand, manufacturer, tag, category, ... );

  • Statistical boosting (by using Events API to report events like product and to cart clicks, LupaSearch can boost products by their popularity).

All types of boosting can be used together. However, boosting (except for phrase boosting) cannot be used together with sort or collapse fields in the same query.

You can also control boosting settings from the dashboard in a selected query configuration.

Important: boosting (except for phrase boosting) cannot be applied together with any initial sort parameters. Also, if public query is executed with any specific sort request, boosting configuration is ignored.

Boost phrase

To enable boosting by exact phrase match, use the following configuration:

{
  "configuration": {
    "selectFields": ["title"],
    "queryFields": { "title": 1 },
    "boostPhrase": {
      "boost": 2,
      "proximity": 1
    }
  }
}
  • boost - controls the boosting strength;

  • proximity - controls the maximum gap between query word match for it to be boosted. For example, "proximity": 1, allows one word gap between boostable phrase: product name one two three would still be boosted for a user query one three.

Numeric boosting

Numerical boosting is configured as a key value pair of a boostable field and it's boosting factor. For example, the following configuration boosts products that have a higher discount and more reviews, while giving more importance to the former:

{
  "configuration": {
    "selectFields": ["title"],
    "queryFields": { "title": 1 },
    "boost": {
      "rating_count": 1.5,
      "discount": 5
    }
  }
}

Value boosting

Value boosting can be configured for a multiple fields, each with a map of key value pairs of boostable values and their importance:

{
  "configuration": {
    "selectFields": ["title"],
    "queryFields": { "title": 1 },
    "boost": {
      "brand": {
        "nike": 5,
        "adidas": 2.5
      },
      "category": {
        "Mobile Phones": 18,
        "Books": 20
      }
    }
  }
}

Limitation: every field can have up to 15 different boostable values.

Statistical boosting

Global scope statistical boosting can be configured using the following settings:

{
  "configuration": {
    "selectFields": ["title"],
    "queryFields": { "title": 1 },
    "statisticalBoost": {
      "itemClick": 1.5,
      "addToCart": 2.5
    }
  }
}

Key value pairs inside statisticalBoost parameter describe the importance of

  • itemClick - boost factor for a number of times that a product was clicked;

  • addToCart - boost factor for a number of times that a product was added to the cart;

For statistical boosting to work, your e-shop needs to report significant events using Events API. If Events API was just implemented in your website, it might take a couple of days until the first results are aggregated by LupaSearch for statistical boosting to work.

Phrase click scope statistical boosting

Phrase click scope statistical boosting facilitates a tailored boosting scope for a specific search phrase.

Consider a scenario where several users search for tv and consistently click on the third item in the results. In response to this behavior, the next time users search for tv, this item will be prioritized to appear in the first position. However, this boosting only applies to the specific search phrase that has resulted in multiple clicks for the item. If the item did not receive any clicks for other search phrases, it won't be boosted.

Configuration for phrase scope statistical boosting can be executed as follows:

{
  "configuration": {
    "selectFields": ["title"],
    "queryFields": { "title": 1 },
    "statisticalBoost": {
      "phraseClickBoost": {
        "weight": 50,
        "minClickCount": 3
      }
    }
  }
}

Available options include:

  • weight - a multiplier used to increase the boosted item's relevance.

  • minClickCount - a control that determines the minimum number of clicks an item should have received for a specific search phrase to qualify for the phrase click boost.

The phrase click boost can be utilized with or without global scope boosting.

Match Type

You can use matchType to control how strict your Query is when matching documents to user queries.

Match Type - any

If matchType is set to any (which is default value), results will include documents that match ANY of the words in user query.

For example, if query is configured to use match type any:

{
  "configuration": {
    "selectFields": ["title"],
    "queryFields": { "title": 1 },
    "matchType": "any"
  }
}

And Public query is:

{
  "searchText": "Samsung television"
}

The results will include matches of ANY of the words in user query:

{
  "searchText": "Samsung television",
  "total": 4,
  "items": [
    { "title": "Samsung A1 Television" },
    { "title": "Samsung A2 Television" },
    { "title": "LG Television" },
    { "title": "Samsung Galaxy Tab Tablet" }
  ]
}

Best and exact matches will still stay on top of results.

Match Type - all

If matchType is set to all, results will include documents that match ALL of the words in user query.

For example, if query is configured to use match type all:

{
  "configuration": {
    "selectFields": ["title"],
    "queryFields": { "title": 1 },
    "matchType": "all"
  }
}

And Public query is:

{
  "searchText": "Samsung television"
}

The results will only include documents, where title matches ALL of the words in user query.

{
  "searchText": "Samsung television",
  "total": 2,
  "items": [
    { "title": "Samsung television a1" },
    { "title": "Samsung television a2" }
  ]
}

Match type cannot be overridden in Public Query request.

Collapse field

There could be a use case where you would like to only show one top search result for a particular product grouping, like one item per variant or any other field.

It is possible to use collapse property, which configures query to only return one top result for each unique value of the configured collapse field:

{
  "configuration": {
    "collapse": {
      "field": "grouping_field"
    }
  }
}

For example, given the document set:

{
  "documents": [
    { "id": 1, "title": "product-1 variant-1", "parent_id": "product-1" },
    { "id": 2, "title": "product-1 variant-2", "parent_id": "product-1" },
    { "id": 3, "title": "product-2 variant-1", "parent_id": "product-2" },
    { "id": 4, "title": "product-2 variant-2", "parent_id": "product-2" },
    { "id": 5, "title": "product-3 variant-1", "parent_id": "product-3" },
    { "id": 6, "title": "product-3 variant-2", "parent_id": "product-3" }
  ]
}

And collapse property set to:

{
  "configuration": {
    "collapse": {
      "field": "parent_id"
    }
  }
}

Search query for all items would return the following results:

{
  "searchText": "",
  "total": 3,
  "items": [
    {
      "id": 1,
      "title": "product-1 variant-1",
      "parent_id": "product-1",
      "_collapsedItemsCount": 2
    },
    {
      "id": 3,
      "title": "product-2 variant-1",
      "parent_id": "product-2",
      "_collapsedItemsCount": 2
    },
    {
      "id": 5,
      "title": "product-3 variant-1",
      "parent_id": "product-3",
      "_collapsedItemsCount": 2
    }
  ]
}

Note the special LupaSearch property _collapsedItemsCount returned with each document.

Did You Mean

Spellcheck or "Did You Mean" functionality, if enabled, can suggest user words or phrases, if their original query returned a small number of relevant results, and it likely that a spelling mistake might have been made.

For example:

  • ferari -> ferrari;

  • bok -> book;

  • telephne -> telephone;

Words and phrases will only be suggested if they are present in your product feed fields that are marked as suggestable in the Search Index mapping.

"Did You Mean" Configuration example:

{
  "configuration": {
    "didYouMean": {
      "threshold": 15,
      "replaceOnNoResults": true
    }
  }
}
  • threshold - "Did You Mean" functionality will only kick-in, if the number of original query results is less than configured threshold;

  • replaceOnNoResults - if set to true, query response items will be automatically replaced with suggested phrase results, if original query yielded zero results.

If original query returns less results than configured threshold (but more than 0), the response will include didYouMean property:

{
  "searchText": "tomatos",
  "total": 1,
  "items": [{}],
  "limit": 10,
  "didYouMean": { "options": [{ "text": "tomatoes", "count": 70 }] }
}
  • didYouMean.options[0].text - a suggested phrase;

  • didYouMean.options[0].count - a number of search results that the suggested phrase matches in your product feed.

It is common to suggest the returned phrase to the user as an alternative to his original query.

If the original query returns zero results, and replaceOnNoResults is set to true, original items will be replaced with results from a new query, and suggested search phrase will be returned as a suggestedSearchText property.

{
  "searchText": "jewelery",
  "total": 281,
  "items": [{}, {}],
  "limit": 10,
  "suggestedSearchText": "jewelry"
}

If the original query returns zero results, but replaceOnNoResults is disabled, the response will include didYouMean object as in the first example.

Important: For a spellcheck to work, at least one of your query fields, has to have suggestable property set in your Search Index Mapping.

Similar Queries

Similar queries help decrease the occurrence of zero-result searches.

They operate by analyzing a multi-word search term entered by a user, then generating suggestions that include shorter variants of the initial phrase.

For instance, if a user's search for electronic mouse yields few or no results, the similar query function will re-run the search using shorter, individual terms—electronic and mouse in this case. It then presents the results from each term as separate result sets.

Similar queries property has the following configuration:

{
  "configuration": {
    "similarQueries": {
      "threshold": 5,
      "limit": 3,
      "documentsPerQuery": 3
    }
  }
}
  • threshold "Similar Query" functionality will be enabled, if the number of original query results is less than configured threshold. Must be between 1 and 20;

  • limit - control the maximum number of returned similar queries. Must be between 1 and 5;

  • documentsPerQuery - control the maximum number of returned documents for each of the returned similar query. Must be between 1 and 10.

If similar query functionality would kick-in, the public query response would look like this:

{
  "searchText": "electronic mouse",
  "total": 0,
  "items": [],
  "similarQueries": [
    {
      "count": 7,
      "query": "mouse",
      "items": [{}, {}, {}],
      "wordCount": 1,
      "displayQuery": "<del>electronic</del> mouse"
    },
    {
      "count": 1,
      "query": "electronic",
      "items": [{}],
      "wordCount": 1,
      "displayQuery": "electronic <del>mouse</del>"
    }
  ]
}

Each similar query will have the following fields:

  • query - suggested similar query, a subset of original phrase;

  • items - an array of top matching documents, no more that configured documentsPerQuery amount;

  • count - total number documents that match the query;

  • wordCount - word count in the returned similar query phrase.

  • displayQuery - an html string that displays original query with strikeout words (for example: electronic mouse). You can use this field to display similar query selection to the user (make sure to use field html, user inputs are escaped by LupaSearch)

Similar Results

The similarResults feature enhances search capabilities by integrating advanced visual and semantic analysis. It leverages embeddings to calculate and retrieve search results based on visual and semantic similarities. This feature is designed to provide more relevant and closely related results, enhancing the user experience in finding content that closely aligns with their search criteria.

Similar results feature has the following configuration:

{
  "similarResults": {
    "visual": {
      "threshold": 5,
      "limit": 10,
      "minAcceptableScore": 0.65,
      "thresholdDistanceFactor": 0.2
    },
    "semantic": {
      "threshold": 5,
      "limit": 10,
      "minAcceptableScore": 0.65,
      "thresholdDistanceFactor": 0.2
    }
  }
}

Parameters:

  • threshold - this parameter determines when the similar results feature is activated. If the count of primary search results is equal to or less than this threshold, similar results are displayed to the user.
  • limit - specifies the maximum number of similar results that can be displayed. This allows for control over the quantity of results presented.
  • minAcceptableScore - sets the benchmark for the quality of similar results. Only results scoring above this minimum acceptable score are displayed, ensuring relevance and quality.
  • thresholdDistanceFactor - represents the allowable distance between the highest scoring result and the lowest acceptable score, expressed as a percentage of the top score. This factor helps in fine-tuning the range of results considered as similar.

Enabling the feature: To enable the similarResults feature, users are required to contact support. This allows for a tailored setup and configuration, ensuring that the feature aligns with specific user needs and preferences. The support team can assist in configuring the parameters to best match the search context and objectives of the user.

Response example:

{
  "searchText": "Vintage Cars",
  "similarResults": {
    "items": [
      { "id": 101, "title": "Classic Ford Mustang", "category": "Automobiles" },
      {
        "id": 102,
        "title": "Vintage Chevrolet Corvette",
        "category": "Automobiles"
      },
      {
        "id": 103,
        "title": "Retro Style Mercedes Benz",
        "category": "Automobiles"
      }
    ],
    "total": 3
  }
}

AI Synonyms

LupaSearch AI synonyms can be enabled by setting aiSynonyms setting:

{
  "configuration": {
    "aiSynonyms": {
      "enabled": true,
      "threshold": 5,
      "behavior": "similarQueries"
    }
  }
}
  • enabled - set to true to enable AI synonym functionality;

  • threshold - AI synonyms functionality will be enalbed, if the number of original query results is less than configured threshold. Must be between 1 and 20;

  • behavior - sets the behavior of AI synonyms. Can be either similarQueries or didYouMean. Their differences are explained below.

If behavior is set to similarQueries, AI synonyms will be returned as additional similar queries in the response:

{
  "searchText": "mouse",
  "total": 0,
  "items": [],
  "similarQueries": [
    {
      "count": 181,
      "items": [{}, {}, {}],
      "query": "AI suggestion 1"
    },
    {
      "count": 28,
      "items": [{}, {}, {}],
      "query": "AI suggestion 2"
    }
  ]
}

If behavior is set to didYouMean, AI synonyms will be added into the main results with the same format and logic as didYouMean spellcheck results.

If original query returns less results than configured threshold (but more than 0), the response will include didYouMean property:

{
  "searchText": "salami",
  "total": 1,
  "items": [{}],
  "limit": 10,
  "didYouMean": { "options": [{ "text": "sausage", "count": 70 }] }
}

If the original query returns zero results, and replaceOnNoResults is set to true on didYouMean configuration, original items will be replaced with results from a new query, and suggested AI phrase will be returned as a suggestedSearchText property.

{
  "searchText": "herring",
  "total": 281,
  "items": [],
  "limit": 10,
  "suggestedSearchText": "fish"
}

AI suggestions are available for all of the languages that LupaSeach supports.

Personalization

Personalization allows to tailor the ranking of the search results for a specific user, according to his previous searches and interactions (using Events API).

Personalization can be enabled in Search Query configuration:

{
  "configuration": {
    "personalization": {
      "enabled": true,
      "eventWeight": {
        "itemClick": 10,
        "addToCart": 40
      }
    }
  }
}
  • enabled - set to true to enable personalization;

  • eventWeight.itemClick - importance of "Item click" events for results personalization;

  • eventWeight.addToCart - importance of "Add to cart" events for results personalization.

Personalization uses configured query facets (to boost results by user preferred categories, tags or other field), so make sure to include at least one term facet field in a query.

For personalization to work, Public Query requests must include userId parameter (which should match one sent with the Events API):

{
  "searchText": "tv",
  "userId": "x-user-id-1"
}

Dynamic properties

Dynamic properties (e.g., attr_*) can be used in the query configuration just like static properties. However, there are some limitations depending on the query configuration field.

Abstract dynamic properties

Configuration fields like selectFields, queryFields, selectableFields, filterableFields allow specifying the abstract dynamic properties:

{
  "configuration": {
    "selectFields": ["id", "attr_*"],
    "queryFields": {
      "id": 1,
      "attr_*": 15
    }
  }
}

However, if the need arises, you can also specify exact property names:

{
  "configuration": {
    "selectFields": ["id", "attr_color", "attr_tag"],
    "queryFields": {
      "id": 1,
      "attr_color": 2,
      "attr_tag": 3
    }
  }
}

Exact name dynamic properties

For all other fields (facets, filters, boost, etc.) the exact dynamic property name is required, and abstract dynamic properties with the asterisk * are not acceptable:

{
  "configuration": {
    "facets": [
      {
        "type": "terms",
        "key": "attr_color",
        "label": "Color"
      },
      {
        "type": "terms",
        "key": "attr_tag",
        "label": "Tag"
      }
    ]
  }
}

The use of the dynamic property asterisk * in these configurations is invalid. Please ensure you provide the exact property names.