Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

%load_ext autoreload
%autoreload 2
import json
import mycode.metrics as metrics
import mycode.utils as u
import mycode.vap as vap
# The goal is to show that Vespa does `.fill()` when there is no need for that.
# Create a sample VAP
from vespa.package import (ApplicationPackage, Field, Schema, Document, RankProfile, Function)

doc_schema = Schema(
    name="doc",
    document=Document(
        fields=[
            Field(
                name="id",
                type="int",
                indexing=["attribute"],
                attribute=["fast-search"],
            ),
        ]
    ),
    rank_profiles=[
        RankProfile(
            name='fields',
            inherits='unranked',
            first_phase="0",
            functions=[
                Function(
                    name='id',
                    expression='attribute(id)'
                )
            ],
            match_features=[
                'id'
            ],
        )
    ]
)

application_package = ApplicationPackage(
    name="test",
    schema=[doc_schema],
)
from vespa.deployment import VespaDocker

# In case running colima on macos run the following
# !sudo ln -sf $HOME/.colima/default/docker.sock /var/run/docker.sock
vespa_docker = VespaDocker(
    container_image="vespaengine/vespa:8.588.8",
)
# Start a docker container and deploy the application package
client = vespa_docker.deploy(
    application_package=application_package,
)
Waiting for configuration server, 0/60 seconds...
Waiting for configuration server, 5/60 seconds...
Waiting for application to come up, 0/300 seconds.
Waiting for application to come up, 5/300 seconds.
Waiting for application to come up, 10/300 seconds.
Application is up!
Finished deployment.
# Create and feed 1 dummy doc
docs = [
    {
        'id': f'{1}',
        'fields': {
            'id': 1,
        }
    }
]

client.feed_iterable(docs, schema="doc", namespace="doc", callback=vap.feed_callback)
no_hacks_resp = client.query(body={
    'yql': 'select matchfeatures from sources * where true',
    'ranking': 'fields',
    'presentation.summary': 'default',
    'trace.level': 6,
}).json
no_hacks_resp
trace_json = json.dumps(no_hacks_resp['trace'], indent=2)
print(u.find_matches_with_context(trace_json, 'Ignoring', 6))
              "message": "Sending 1 summary fetch requests with jrt/protobuf"
            },
            {
              "message": "Not resending query during document summary fetching"
            },
            {
              "message": "Ignoring fill(default): Hits already filled: result.hits().getFilled()=[[presentation], [f:documentid,matchfeatures,rankfeatures,summaryfeatures], [f:matchfeatures]]"
            }
          ]
        },
        {
          "message": "Got 1 hits from source:test_content"
        },
# ^ As expected: one call to Vespa to get the summary class, and on the second take fill is ignored. This is problematic because we want to avoid roundtrip to content nodes.
# Let's build a bundle that hacks the `.fill()` behaviour
# The relevant Java code is here:
!cat ../examples/ignore-fill-bundle/src/main/java/lt/jocas/examples/SkipFillSearcher.java
package lt.jocas.examples;

import com.yahoo.prelude.fastsearch.PartialSummaryHandler;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
import com.yahoo.search.searchchain.Execution;

import java.util.Set;

import static com.yahoo.prelude.fastsearch.PartialSummaryHandler.PRESENTATION;

public class SkipFillSearcher extends Searcher {

    @Override
    public Result search(Query query, Execution execution) {
        return execution.search(query);
    }

    private static final Set<String> IGNORED_SUMMARY_FIELDS = Set.of("matchfeatures");

    private boolean isFillIgnorable(String summaryClass, Result result) {
        return PRESENTATION.equals(summaryClass) &&
                result.getQuery().getPresentation().getSummaryFields().equals(IGNORED_SUMMARY_FIELDS);
    }

    @Override
    public void fill(Result result, String summaryClass, Execution execution) {
        var adjustedSummaryClass = summaryClass;
        if (isFillIgnorable(summaryClass, result)) {
            // The `default` class works here because later Searcher class Vespa
            // checks that only some fields are needed
            // https://github.com/vespa-engine/vespa/blob/5dbf6c9d7feecd452dff7d494c540b0d31cf02bc/container-search/src/main/java/com/yahoo/prelude/fastsearch/PartialSummaryHandler.java#L239-L248
            // and creates synthetic names for which it checks
            // https://github.com/vespa-engine/vespa/blob/74e5c519e3d392b8ef34ced618fb90c7910adeb9/container-search/src/main/java/com/yahoo/search/Searcher.java#L164
            // whether they are already fetched,
            // thus declaring that for `.fill()` there is nothing to do.
            // Or this can be set to null, the effect is the same.
            adjustedSummaryClass = PartialSummaryHandler.DEFAULT_CLASS;
        }
        execution.fill(result, adjustedSummaryClass);
    }
}
# Package into a bundle jar
!(cd ../examples/ignore-fill-bundle && mvn -f pom.xml package)
# There should be a file `../examples/ignore-fill-bundle/target/ignore-fill-bundle-0.0.1-deploy.jar`
!ls -alh ../examples/ignore-fill-bundle/target/ignore-fill-bundle-0.0.1-deploy.jar
[INFO] Scanning for projects...
[INFO] 
[INFO] ----------------< lt.jocas.examples:ignore-fill-bundle >----------------
[INFO] Building ignore-fill-bundle 0.0.1
[INFO]   from pom.xml
[INFO] --------------------------[ container-plugin ]--------------------------
Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-resources-plugin/maven-metadata.xml
Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-resources-plugin/maven-metadata.xml (988 B at 2.3 kB/s)
[WARNING] Ignoring incompatible plugin version 4.0.0-beta-1: The plugin org.apache.maven.plugins:maven-resources-plugin:4.0.0-beta-1 requires Maven version 4.0.0-beta-3
[INFO] Latest version of plugin org.apache.maven.plugins:maven-resources-plugin failed compatibility check
[INFO] Looking for compatible RELEASE version of plugin org.apache.maven.plugins:maven-resources-plugin
[INFO] Selected plugin org.apache.maven.plugins:maven-resources-plugin:3.3.1
Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-surefire-plugin/maven-metadata.xml
Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-surefire-plugin/maven-metadata.xml (2.4 kB at 22 kB/s)
Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-install-plugin/maven-metadata.xml
Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-install-plugin/maven-metadata.xml (964 B at 5.7 kB/s)
[WARNING] Ignoring incompatible plugin version 4.0.0-beta-2: The plugin org.apache.maven.plugins:maven-install-plugin:4.0.0-beta-2 requires Maven version 4.0.0-rc-2
[INFO] Latest version of plugin org.apache.maven.plugins:maven-install-plugin failed compatibility check
[INFO] Looking for compatible RELEASE version of plugin org.apache.maven.plugins:maven-install-plugin
[WARNING] Ignoring incompatible plugin version 4.0.0-beta-1: The plugin org.apache.maven.plugins:maven-install-plugin:4.0.0-beta-1 requires Maven version 4.0.0-beta-3
[INFO] Selected plugin org.apache.maven.plugins:maven-install-plugin:3.1.4
Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-deploy-plugin/maven-metadata.xml
Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-deploy-plugin/maven-metadata.xml (1.1 kB at 8.8 kB/s)
[WARNING] Ignoring incompatible plugin version 4.0.0-beta-2: The plugin org.apache.maven.plugins:maven-deploy-plugin:4.0.0-beta-2 requires Maven version 4.0.0-rc-2
[INFO] Latest version of plugin org.apache.maven.plugins:maven-deploy-plugin failed compatibility check
[INFO] Looking for compatible RELEASE version of plugin org.apache.maven.plugins:maven-deploy-plugin
[WARNING] Ignoring incompatible plugin version 4.0.0-beta-1: The plugin org.apache.maven.plugins:maven-deploy-plugin:4.0.0-beta-1 requires Maven version 4.0.0-beta-3
[INFO] Selected plugin org.apache.maven.plugins:maven-deploy-plugin:3.1.4
[INFO] 
[INFO] --- vespa-bundle:8.588.8:generateSources (default-generateSources) @ ignore-fill-bundle ---
[WARNING] Did not find either container or container-dev artifact in project dependencies, using default version '8.588.8' of the config class plugin.
[INFO] 
[INFO] --- resources:3.3.1:resources (default-resources) @ ignore-fill-bundle ---
[INFO] skip non existing resourceDirectory /Users/dainius.jocas/p/lab/examples/ignore-fill-bundle/src/main/resources
[INFO] 
[INFO] --- compiler:3.11.0:compile (default-compile) @ ignore-fill-bundle ---
[INFO] Changes detected - recompiling the module! :source
[INFO] Compiling 1 source file with javac [debug target 17] to target/classes
[WARNING] system modules path not set in conjunction with -source 17
[INFO] 
[INFO] --- resources:3.3.1:testResources (default-testResources) @ ignore-fill-bundle ---
[INFO] skip non existing resourceDirectory /Users/dainius.jocas/p/lab/examples/ignore-fill-bundle/src/test/resources
[INFO] 
[INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ ignore-fill-bundle ---
[INFO] No sources to compile
[INFO] 
[INFO] --- surefire:3.5.4:test (default-test) @ ignore-fill-bundle ---
[INFO] No tests to run.
[INFO] 
[INFO] --- vespa-bundle:8.588.8:generate-osgi-manifest (default-generate-osgi-manifest) @ ignore-fill-bundle ---
[INFO] 
[INFO] --- vespa-bundle:8.588.8:assemble-container-plugin (default-assemble-container-plugin) @ ignore-fill-bundle ---
[INFO] Building jar: /Users/dainius.jocas/p/lab/examples/ignore-fill-bundle/target/ignore-fill-bundle-0.0.1-without-dependencies.jar
[INFO] Building jar: /Users/dainius.jocas/p/lab/examples/ignore-fill-bundle/target/ignore-fill-bundle-0.0.1-deploy.jar
[INFO] 
[INFO] --- vespa-app:8.588.8:packageApplication (default) @ ignore-fill-bundle ---
[INFO] Copying bundle to application: ignore-fill-bundle-0.0.1-deploy.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.186 s
[INFO] Finished at: 2025-10-14T12:55:46+03:00
[INFO] ------------------------------------------------------------------------
-rw-r--r--@ 1 dainius.jocas  staff   4.3K Oct 14 12:55 ../examples/ignore-fill-bundle/target/ignore-fill-bundle-0.0.1-deploy.jar
# Now let's prepare another application package with the new search chain
from vespa.package import ServicesConfiguration
from vespa.configuration.services import services, container, document_api, search, chain, searcher, document_processing, content, documents, document, redundancy

services_config = ServicesConfiguration(
    application_name="test",
    services_config=services(
        container(
            document_api(),
            document_processing(),
            search(
                chain(
                    searcher(
                        id="lt.jocas.examples.SkipFillSearcher",
                        bundle="ignore-fill-bundle",
                    ),
                    id="fields",
                    inherits='vespa'
                )
            ),
            id="test_container",
            version="1.0"
        ),
        content(
            redundancy(1),
            documents(
                document(type="doc", mode="index"),
            ),
            id="test_content",
            version="1.0"
        )
    )
)

application_package = ApplicationPackage(
    name='test',
    schema=[doc_schema],
    services_config=services_config
)

# Currently, pyvespa provides no way to add bundle jars nicely into VAP
# So, we need to do a little dance and add it manually.

tmp_vap_folder = '_tmp'
application_package.to_files(tmp_vap_folder)

vap.add_bundles(
    application_root=tmp_vap_folder,
    bundles=['../examples/ignore-fill-bundle/target/ignore-fill-bundle-0.0.1-deploy.jar']
)

client = vap.redeploy_from_disk(
    docker=vespa_docker,
    application_root=tmp_vap_folder
)
# Let's add the 'searchChain': 'fields',
no_summary_resp = client.query(body={
    'yql': 'select matchfeatures from sources * where true',
    'ranking': 'fields',
    'presentation.summary': 'default',
    'trace.level': 6,
    'searchChain': 'fields',
}).json
no_summary_resp
{'trace': {'children': [{'message': "Using query profile 'default' of type 'root'"}, {'message': 'Resolved properties:\n'}, {'message': "Invoking chain 'fields' [lt.jocas.examples.SkipFillSearcher@fields -> com.yahoo.prelude.statistics.StatisticsSearcher@native -> ... -> federation@native]"}, {'children': [{'timestamp': 0, 'message': "Invoke searcher 'lt.jocas.examples.SkipFillSearcher in fields'"}, {'timestamp': 0, 'message': "Invoke searcher 'com.yahoo.prelude.statistics.StatisticsSearcher in native'"}, {'timestamp': 0, 'message': "Invoke searcher 'com.yahoo.prelude.querytransform.PhrasingSearcher in vespa'"}, {'timestamp': 0, 'message': "Invoke searcher 'com.yahoo.prelude.searcher.FieldCollapsingSearcher in vespa'"}, {'timestamp': 0, 'message': "Invoke searcher 'com.yahoo.search.yql.MinimalQueryInserter in vespa'"}, {'message': 'YQL query parsed: [\nselect matchfeatures from sources * where true\nTRUE\n]'}, {'timestamp': 1, 'message': "Invoke searcher 'com.yahoo.search.yql.FieldFilter in vespa'"}, {'timestamp': 1, 'message': "Invoke searcher 'com.yahoo.prelude.searcher.JuniperSearcher in vespa'"}, {'timestamp': 1, 'message': "Invoke searcher 'com.yahoo.prelude.searcher.PosSearcher in vespa'"}, {'timestamp': 1, 'message': "Invoke searcher 'com.yahoo.prelude.semantics.SemanticSearcher in vespa'"}, {'timestamp': 1, 'message': "Invoke searcher 'com.yahoo.search.grouping.GroupingQueryParser in vespa'"}, {'timestamp': 1, 'message': "Invoke searcher 'com.yahoo.prelude.searcher.BlendingSearcher in vespa'"}, {'timestamp': 1, 'message': "Invoke searcher 'com.yahoo.search.querytransform.WeakAndReplacementSearcher in vespa'"}, {'timestamp': 1, 'message': "Invoke searcher 'com.yahoo.search.searchers.OpportunisticWeakAndSearcher in vespa'"}, {'timestamp': 1, 'message': "Invoke searcher 'federation in native'"}, {'message': 'Federating to [test_content]'}, {'timestamp': 2, 'children': [{'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.search.querytransform.NGramSearcher in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.search.querytransform.DefaultPositionSearcher in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.prelude.querytransform.CJKSearcher in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.prelude.querytransform.LiteralBoostSearcher in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.search.querytransform.RangeQueryOptimizer in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.search.querytransform.SortingDegrader in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.search.searchers.QueryValidator in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.search.grouping.GroupingValidator in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.search.querytransform.WandSearcher in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.prelude.querytransform.RecallSearcher in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.search.searchers.ValidateNearestNeighborSearcher in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.search.searchers.ValidateMatchPhaseSearcher in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.search.searchers.ValidateFuzzySearcher in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.search.searchers.ValidateSameElementSearcher in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.search.yql.FieldFiller in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.search.searchers.InputCheckingSearcher in test_content'"}, {'timestamp': 2, 'message': "Invoke searcher 'com.yahoo.search.significance.SignificanceSearcher in test_content'"}, {'timestamp': 3, 'message': "Invoke searcher 'com.yahoo.prelude.querytransform.StemmingSearcher in test_content'"}, {'message': 'Stemming with language ENGLISH using OpenNlpLinguistics'}, {'message': 'Stemming: [\nselect matchfeatures from sources * where true timeout 495\nTRUE\n]'}, {'timestamp': 3, 'message': "Invoke searcher 'com.yahoo.prelude.querytransform.NormalizingSearcher in test_content'"}, {'timestamp': 3, 'message': "Invoke searcher 'com.yahoo.search.querytransform.VespaLowercasingSearcher in test_content'"}, {'message': 'Lowercasing: [\nselect matchfeatures from sources * where true timeout 495\nTRUE\n]'}, {'timestamp': 3, 'message': "Invoke searcher 'com.yahoo.prelude.searcher.ValidateSortingSearcher in test_content'"}, {'timestamp': 3, 'message': "Invoke searcher 'com.yahoo.search.querytransform.BooleanSearcher in test_content'"}, {'message': 'BooleanSearcher: Nothing added to query'}, {'timestamp': 3, 'message': "Invoke searcher 'com.yahoo.search.grouping.vespa.GroupingExecutor in test_content'"}, {'timestamp': 3, 'message': "Invoke searcher 'com.yahoo.prelude.searcher.ValidatePredicateSearcher in test_content'"}, {'timestamp': 3, 'message': "Invoke searcher 'com.yahoo.search.searchers.ContainerLatencySearcher in test_content'"}, {'timestamp': 3, 'message': "Invoke searcher 'com.yahoo.prelude.cluster.ClusterSearcher in test_content'"}, {'message': 'test_content.num0 search to dispatch: query=[TRUE] timeout=495ms offset=0 hits=10 rankprofile[fields] groupingSessionCache=true sessionId=8d4a74fb-bd00-4a9f-ac78-2d9b1be6db48.1760435790126.3.fields grouping=0 : restrict=[doc]'}, {'message': 'Current state of query tree: TRUE'}, {'message': 'YQL+ representation: select matchfeatures from sources * where true timeout 495'}, {'message': 'Dispatching to search node in cluster = dispatcher.test_content key = 0 hostname = test path = 0 in group 0 statusIsKnown = true working = true activeDocs = 1 targetActiveDocs = 1'}, {'message': 'Sending search request with jrt/protobuf to node with dist key 0'}, {'message': [{'start_time': '2025-10-14 09:56:30.129 UTC', 'traces': [{'timestamp_ms': 0.493541, 'event': 'searching for 10 hits at offset 0', 'tag': 'query_start'}, {'traces': [{'timestamp_ms': 0.648458, 'event': 'Start query setup'}, {'timestamp_ms': 0.657583, 'event': 'Deserialize and build query tree'}, {'timestamp_ms': 0.698958, 'event': 'Build query execution plan'}, {'timestamp_ms': 0.710458, 'event': 'Optimize query execution plan'}, {'timestamp_ms': 0.752458, 'event': 'Perform dictionary lookups and posting lists initialization'}, {'timestamp_ms': 0.757458, 'event': 'Prepare shared state for multi-threaded rank executors'}, {'timestamp_ms': 0.791916, 'event': 'Complete query setup'}], 'timestamp_ms': 0.796833, 'tag': 'query_setup'}, {'timestamp_ms': 0.825124, 'tag': 'query_execution_plan', 'optimized': {'[type]': 'proton::documentmetastore::(anonymous namespace)::WhiteListBlueprint', 'isTermLike': False, 'estimate': {'[type]': 'HitEstimate', 'empty': False, 'estHits': 2, 'cost_tier': 2, 'tree_size': 1, 'allow_termwise_eval': True}, 'relative_estimate': 1.0, 'cost': 1.0, 'strict_cost': 1500.0, 'sourceId': 4294967295, 'docid_limit': 2, 'id': 1, 'strict': True}}, {'timestamp_ms': 1.219749, 'tag': 'query_execution', 'threads': [{'traces': [{'timestamp_ms': 0.928707, 'event': 'Start MatchThread::run'}, {'timestamp_ms': 1.050791, 'event': 'Start match and first phase rank'}, {'timestamp_ms': 1.062332, 'event': 'Create result set'}, {'timestamp_ms': 1.086874, 'event': 'Wait for result processing token'}, {'timestamp_ms': 1.089041, 'event': 'Start result processing'}, {'timestamp_ms': 1.095207, 'event': 'Start thread merge'}, {'timestamp_ms': 1.100666, 'event': 'MatchThread::run Done'}]}]}, {'timestamp_ms': 1.274624, 'event': 'returning 1 hits from total 1', 'tag': 'query_reply'}], 'distribution-key': 0, 'document-type': 'doc', 'duration_ms': 1.281624}]}, {'message': 'test_content.num0 dispatch response: Result (1 of total 1 hits)'}, {'message': 'test_content.num0 returns:\n #: 0, relevancy: 0.0, source: test_content.num0, uri: null\n'}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.prelude.cluster.ClusterSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.searchers.ContainerLatencySearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.prelude.searcher.ValidatePredicateSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.grouping.vespa.GroupingExecutor in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.querytransform.BooleanSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.prelude.searcher.ValidateSortingSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.querytransform.VespaLowercasingSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.prelude.querytransform.NormalizingSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.prelude.querytransform.StemmingSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.significance.SignificanceSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.searchers.InputCheckingSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.yql.FieldFiller in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.searchers.ValidateSameElementSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.searchers.ValidateFuzzySearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.searchers.ValidateMatchPhaseSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.searchers.ValidateNearestNeighborSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.prelude.querytransform.RecallSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.querytransform.WandSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.grouping.GroupingValidator in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.searchers.QueryValidator in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.querytransform.SortingDegrader in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.querytransform.RangeQueryOptimizer in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.prelude.querytransform.LiteralBoostSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.prelude.querytransform.CJKSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.querytransform.DefaultPositionSearcher in test_content'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.querytransform.NGramSearcher in test_content'"}]}, {'message': 'Got 1 hits from source:test_content'}, {'timestamp': 9, 'message': "Return searcher 'federation in native'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.searchers.OpportunisticWeakAndSearcher in vespa'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.querytransform.WeakAndReplacementSearcher in vespa'"}, {'message': 'Blended result returns:\n #: 0, relevancy: 0.0, source: test_content, uri: null\n'}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.prelude.searcher.BlendingSearcher in vespa'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.grouping.GroupingQueryParser in vespa'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.prelude.semantics.SemanticSearcher in vespa'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.prelude.searcher.PosSearcher in vespa'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.prelude.searcher.JuniperSearcher in vespa'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.yql.FieldFilter in vespa'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.search.yql.MinimalQueryInserter in vespa'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.prelude.searcher.FieldCollapsingSearcher in vespa'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.prelude.querytransform.PhrasingSearcher in vespa'"}, {'timestamp': 9, 'message': "Return searcher 'com.yahoo.prelude.statistics.StatisticsSearcher in native'"}, {'timestamp': 9, 'message': "Return searcher 'lt.jocas.examples.SkipFillSearcher in fields'"}, {'message': "Invoke fill([presentation]) on searcher 'lt.jocas.examples.SkipFillSearcher in fields'"}, {'message': 'Hits need fill([presentation]); hasFilled=[[f:matchfeatures]] in class lt.jocas.examples.SkipFillSearcher'}, {'message': "Invoke fill(default) on searcher 'com.yahoo.prelude.statistics.StatisticsSearcher in native'"}, {'message': 'Ignoring fill(default): Hits already filled: result.hits().getFilled()=[[f:matchfeatures]]'}, {'message': "Return fill(default) on searcher 'com.yahoo.prelude.statistics.StatisticsSearcher in native'"}, {'message': "Return fill([presentation]) on searcher 'lt.jocas.examples.SkipFillSearcher in fields'"}, {'message': "Query time query 'TRUE': 9 ms"}, {'message': "Summary fetch time query 'TRUE': 1 ms"}, {'message': 'Vespa version: 8.588.8'}]}]}, 'root': {'id': 'toplevel', 'relevance': 1.0, 'fields': {'totalCount': 1}, 'coverage': {'coverage': 100, 'documents': 1, 'full': True, 'nodes': 1, 'results': 1, 'resultsFull': 1}, 'children': [{'id': 'index:test_content.num0/0/c4ca42388ce70a10b392b401', 'relevance': 0.0, 'source': 'test_content', 'fields': {'matchfeatures': {'id': 1.0}}}]}}
trace_json = json.dumps(no_summary_resp['trace'], indent=2)
print(u.find_matches_with_context(trace_json, 'summary', 6))

# ^ no summary is being fetched because trace has no matches.
with_summary_resp = client.query(body={
    'yql': 'select matchfeatures from sources * where true',
    'ranking': 'fields',
    'presentation.summary': 'default',
    'trace.level': 6,
    'searchChain': 'vespa',  # default search chain
    'presentation.timing': True,
}).json
with_summary_resp
trace_json = json.dumps(with_summary_resp['trace'], indent=2)
print(u.find_matches_with_context(trace_json, 'Ignoring', 6))
              "message": "Sending 1 summary fetch requests with jrt/protobuf"
            },
            {
              "message": "Not resending query during document summary fetching"
            },
            {
              "message": "Ignoring fill(default): Hits already filled: result.hits().getFilled()=[[presentation], [f:documentid,matchfeatures,rankfeatures,summaryfeatures], [f:matchfeatures]]"
            }
          ]
        },
        {
          "message": "Got 1 hits from source:test_content"
        },
# ^ When changed searchChain to `vespa`, we once again see that summary is being fetched
# here are the metrics at this point in the content node about docsum
vespa_metrics = metrics.fetch(vespa_docker)
content_node_metrics = metrics.from_search_node(vespa_metrics)
docsum_metrics = metrics.by_name(content_node_metrics, '.*docsum.*')
metrics.pp(docsum_metrics)