Skip to content

Multi-term Queries

Marqo supports weighted multi-term queries. This can be used to inject additional semantics into the query vectors to influence the results, uses include advanced search, personalisation, and quality control.

Multi-term queries are specified as a dictionary where the query term is the key and the weight is the value. The weight can be any floating point number, positive or negative. Vectors for each term are combined as a weighted average using the weights provided, as such a negative weight move search away from that term and a positive term moves towards it.

mq.index("my-first-index").search(
    {
        "red t-shirt": 1.0,
        "short sleeve": 0.3,
        "buttons": -0.4,
        "low resolution, blurry, jpeg artifacts": -0.2,
    }
)

Advanced Search Queries

Our demo website has an implementation of weighted multi-term queries via the "more of" and "less of" input fields. For example you could search "shirt" which will return results with some business shirts, but if you enter "business" into the "less of" field it will remove business shirts from the results.

Under the hood the query construction is implemented as follows (actual implementation here):

def compose_query(
    query: str,
    more_of: str,
    less_of: str,
) -> Dict[str, float]:
    composed_query = {}

    if more_of:
        more_term = query + ", " + more_of  # this trick is explained below
        composed_query[more_term] = 0.75

    if less_of:
        composed_query[less_of] = -1.1

    if query:
        composed_query[query] = 1.0

    if not composed_query:
        return {"": 1}

    return composed_query

This means that a search for "shirt" with more of "buttons" and less of "business" would be transformed into:

{
    "shirt": 1.0,
    "shirt, buttons": 0.75,
    "business": -1.1
}

Prepended Query Term Trick: In this implementation we prepend the query term to the "more of" term. This trick allows for a higher weight on the "more of" term without risking the "more of" term derailing the search and taking over the intended primary search keyword.

Personalisation

Where you have additional information about a user this can be incorporated with low weights into a weighted query to personalise the search results in real-time. For example a users current shopping cart, interaction history, or favourited item list could be used to source text and images to influence search.

A modified version of the advanced search query implementation could be used to incorporate personalisation through favourited items:

def compose_query(
    query: str, more_of: str, less_of: str, favourites: List[str]
) -> Dict[str, float]:
    composed_query = {}

    if more_of:
        more_term = query + ", " + more_of  # this trick is explained below
        composed_query[more_term] = 0.75

    if less_of:
        composed_query[less_of] = -1.1

    if query:
        composed_query[query] = 1.0

    total_fav_weight = 0.2  # we will equally distribute the weight of the favourites
    # favourites could be text or image urls
    for favourite in favourites:
        composed_query[favourite] = total_fav_weight / len(favourites)

    if not composed_query:
        return {"": 1}

    return composed_query

Quality Control

Additional terms can be used to steer search away from low quality, NSFW, or other undesirable results. More examples are provided in the Query Prompt Engineering tips.