vespa

How can I set rank-profile inputs via a query-profile?


I have a Vespa instance that I deploy directly from my Application Package. My document schema includes several rank-profiles that are correctly used in query requests. However, I need to define various query settings for my application and want to set them via query-profiles in Vespa. Settings like userInput or FuzzySearch work as expected, but settings related to rank-profiles do not.

Goal:

I would like to set query conditions like 'input.query(q) = embed(e5,@query)' or 'ranking = "my_rank_profile"' via query-profile.

Part of my document schema:

schema doc {
    document doc {
        field subject type string {
            indexing: summary | attribute | index 
            index: enable-bm25
            attribute {
                fast-search
            }
        }
        field body type array<string> {
            indexing: summary | attribute | index
            index: enable-bm25
            attribute {
                fast-search
            }
        }
    field body_embedding type tensor<bfloat16>(p{},x[1024]) {
        indexing: input body | embed e5 | attribute | index
        attribute {
            distance-metric: angular
        }
        index {
            hnsw {
                max-links-per-node: 16
                neighbors-to-explore-at-insert: 200
            }
        }
    }
    fieldset default {
        fields: subject, body
    }
    rank-profile my_rank_profile {
        inputs {
            query(q) tensor<bfloat16>(x[1024])             
            query(subjectWeight)  : 3            
        }
        function weighted_subject() {
            expression {
                nativeRank(subject) * query(subjectWeight)
            }
        }
        first-phase {
            expression {
                cos(distance(field,body_embedding)) + weighted_subject
            }
        }
        match-features {
            query(subjectWeight)    
            weighted_subject      
            firstPhase
        }
    }
}

Vespa Version: 8.448.13

What works:

<query-profile id="UserInputProfile">
    <field name="yql">select * from sources * where %{user-input}</field>
    <field name="user-input">({targetHits:10, weight:%{.user-input-weight}}userInput(@query))</field>
    <field name="user-input-weight">20</field>
</query-profile>

Request JSON body:

{
    "query": "some user query",
    "queryProfile": "UserInputProfile"
}

What I am trying to do:

Query-profile type:

<query-profile-type id="NearestNeighborTypes">
    <field name="yql" type="string"/>
    <field name="nn-input" type="string"/>
    <field name="input.query(q)" type="tensor(x[1024])"/>
    <field name="input.query(subjectWeight)" type="float"/>
    <field name="ranking" type="string"/>
</query-profile-type>

Query-profile:

<query-profile id="NearestNeighborProfile" type="NearestNeighborTypes">
    <field name="yql">select * from sources * where %{.nn-input} or userQuery()</field>
    <field name="nn-input">({targetHits:10}nearestNeighbor(body_embedding,q))</field>
    <field name="input.query(q)">embed(e5,@query)</field>
    <field name="input.query(subjectWeight)">5</field>
    <field name="ranking">my_rank_profile</field>
</query-profile>

Request JSON body:

{
    "query": "some user query",
    "queryProfile": "NearestNeighborProfile"
}

Expected behavior:

  1. The query would trigger a nearest neighbor search.
  2. The user query would be embedded using the embedder specified in my services.xml.
  3. The my_rank_profile rank-profile would be used, and the match features would appear in the document response.

Actual behavior:

  1. The request works only if I include everything (except the nn-input) directly in the request JSON body.
  2. Instead of embedding the user query, I get the following error:
Uploading application package... failed
Error: invalid application package (status 400)
Invalid application:
Error reading query profile 'NearestNeighborProfile' of type 'NearestNeighborTypes':
Could not set 'input.query(q)' to 'embed(e5,@query)':
Can't find embedder 'e5'. Available embedder ids are 'default'.

In my services.xml, I have the following embedder configuration:

<component id="e5" type="hugging-face-embedder">
    <transformer-model url="https://github.com/vespa-engine/sample-apps/raw/master/simple-semantic-search/model/e5-small-v2-int8.onnx"/>
    <tokenizer-model url="https://raw.githubusercontent.com/vespa-engine/sample-apps/master/simple-semantic-search/model/tokenizer.json"/>
    <prepend> <!-- E5 prompt instructions -->
        <query>query:</query>
        <document>passage:</document>
    </prepend>
</component>

Since it works fine when I directly specify the 'embed(e5,@query)' in the request body, I assume the embedder is correctly registered.

  1. If I remove the nearest neighbor part and only use the userQuery() expression, no errors are thrown, but the rank-profile is not applied, as the match features do not appear in the response. Additionally, when I try to set values like subjectWeight in the query-profile, they are not being applied, and the value in the rank-profile doesn’t adjust based on those inputs.

Question:

Is this behavior not supported by Vespa, or am I doing something wrong?


Solution

  • Try replacing "ranking" with "ranking.profile" - per https://docs.vespa.ai/en/reference/query-api-reference.html this is the full name and https://docs.vespa.ai/en/query-profiles.html#using-a-query-profile you cannot use aliases ("ranking" is an alias).

    I think this will at least solve the problem with the missing ranking profile data