Use this file to discover all available pages before exploring further.
Searchers are the fundamental building blocks for implementing custom query processing and result manipulation in Vespa. They participate in a chain of responsibility pattern where queries pass through a sequence of searchers, each potentially modifying the query or result.
All custom searchers extend the com.yahoo.search.Searcher class and override the search method:
package com.example;import com.yahoo.search.Query;import com.yahoo.search.Result;import com.yahoo.search.Searcher;import com.yahoo.search.searchchain.Execution;public class MySearcher extends Searcher { @Override public Result search(Query query, Execution execution) { // Modify query before passing it on query.properties().set("myProperty", "value"); // Pass query to next searcher in chain Result result = execution.search(query); // Process result before returning result.hits().add(createMyHit()); return result; }}
The searcher is instantiated with its configuration. Build any required in-memory structures here.
public class ConfiguredSearcher extends Searcher { private final String myConfig; public ConfiguredSearcher(MyConfig config) { this.myConfig = config.value(); }}
2
In Service
The search() method is called by multiple threads in parallel. Keep shared data structures immutable or use proper synchronization.
3
Deconstruction
Override deconstruct() to clean up resources. This is called when the searcher is being removed.
@Overridepublic void deconstruct() { super.deconstruct(); // Clean up resources}
import com.yahoo.search.result.Hit;public class ResultEnricherSearcher extends Searcher { @Override public Result search(Query query, Execution execution) { Result result = execution.search(query); // Enrich each hit with additional data for (Hit hit : result.hits()) { hit.setField("enriched", true); hit.setField("timestamp", System.currentTimeMillis()); } return result; }}
import com.yahoo.search.result.Hit;import java.util.List;public class CustomSourceSearcher extends Searcher { @Override public Result search(Query query, Execution execution) { Result result = new Result(query); // Fetch from external source List<MyData> data = fetchFromExternalAPI(query.getModel().getQueryString()); // Convert to hits for (MyData item : data) { Hit hit = new Hit(item.getId()); hit.setField("title", item.getTitle()); hit.setField("content", item.getContent()); hit.setRelevance(item.getScore()); result.hits().add(hit); } return result; } private List<MyData> fetchFromExternalAPI(String query) { // Implementation here return List.of(); }}
Here’s a simplified version of Vespa’s StemmingSearcher from ~/workspace/source/container-search/src/main/java/com/yahoo/prelude/querytransform/StemmingSearcher.java:62:
import com.yahoo.component.annotation.Inject;import com.yahoo.language.Linguistics;import com.yahoo.prelude.IndexFacts;import com.yahoo.search.searchchain.PhaseNames;@After(PhaseNames.UNBLENDED_RESULT)@Provides("Stemming")public class StemmingSearcher extends Searcher { private final Linguistics linguistics; @Inject public StemmingSearcher(ComponentId id, Linguistics linguistics) { super(id); this.linguistics = linguistics; } @Override public Result search(Query query, Execution execution) { if (query.properties().getBoolean("nostemming")) { return execution.search(query); } IndexFacts.Session indexFacts = execution.context().getIndexFacts().newSession(query); // Replace query terms with stems Item newRoot = replaceTerms(query, indexFacts); query.getModel().getQueryTree().setRoot(newRoot); query.trace("Stemming", true, 2); return execution.search(query); } private Item replaceTerms(Query query, IndexFacts.Session indexFacts) { // Stemming logic here return query.getModel().getQueryTree().getRoot(); }}
if (invalidCondition) { return new Result(query, ErrorMessage.createBadRequest("Invalid parameter"));}
Handling Unexpected Events
Throw a RuntimeException:
if (criticalFailure) { throw new RuntimeException("Critical failure: " + details);}
Recoverable User Errors
Add a FeedbackHit explaining the condition:
import com.yahoo.search.result.FeedbackHit;FeedbackHit feedback = new FeedbackHit();feedback.setField("message", "Please correct your query");result.hits().add(feedback);