cal 29 Mar 2024

Semantic search is the process of retrieving information by understanding the meaning behind your query, rather than just matching keywords. For example, if you search for "healthy breakfast recipes," a semantic search engine might return results like "10 Nutritious Breakfast Ideas" or "Quick and Easy Breakfast Options." It considers synonyms, related concepts, and context to provide more relevant results.

Goal

Configure semantic search utilizing e5-small-v2 embedding model

Prerequisites

Before proceeding, ensure Customizing Ranking is completed.

Define Embedding Model in VAP

<component id="e5" type="hugging-face-embedder">
   <transformer-model path="model/e5-small-v2-int8.onnx"/>
   <tokenizer-model path="model/tokenizer.json"/>
</component>

Add Embedding Field

field emb_field type tensor<float>(x[384]) {
        indexing {
            # Initialize variables
            "" | set_var tags_var | set_var description_var | set_var title_var;

            select_input {tags: (input tags | join " ") | set_var tags_var;};
            select_input {description: input description | set_var description_var;};
            select_input {title: input title | set_var title_var;};

           "passage: " . (get_var tags_var) . " " . (get_var description_var) . " " . (get_var title_var)  | embed e5 | attribute | index
        }
    }

Here we concatenate tags, description and title fields to compute embedding using the specified e5 model.

<?xml version="1.0" encoding="UTF-8"?>
<query-profile id="book_ann_v1">
    <field name="maxHits">100</field>
    <field name="maxOffset">100</field>
    <field name="hits">10</field>
    <field name="ranking.profile">ann</field>

    <field name="yql">select * from book where
        ({"targetHits": 100, "label": "nns"}nearestNeighbor(emb_field, embedding))
    </field>

    <field name="ranking.features.query(embedding)">embed(e5, "query: %{search_term}")</field>
    <field name="search_term"></field>
    <field name="timeout">2s</field>
    <field name="rules.off">false</field>
</query-profile>

Here, the ranking.features.query(embedding) field computes the embedding based on the search_term parameter and passes it to the nearestNeighbor function for ranking matching documents.

  • Add a new rank profile based on the nearestNeighbor function:

 rank-profile ann inherits default {
        inputs {
            query(embedding) tensor<float>(x[384])
        }

        function annMatchScore () {
            expression: closeness(label,nns)
        }

        first-phase {
            expression: annMatchScore
        }
    }

Here, label nns refers to the annotation defined in the query-profile.

Let’s search for "huge gem":

curl --location 'http://localhost:8080/search/' \
--header 'Content-Type: application/json' \
--data '{
    "queryProfile": "book_ann_v1",
    "search_term": "huge gem",
    "query_filter": "AND year > 1900"
}'

As anticipated, "The Diamond as Big as the Ritz" receives the highest rank.

Summary

By following these steps, we have configured a semantic search that significantly improves the search quality.

Next Steps

Explore Text-To-Image Search to improve search quality further