Anserini Documentation
repository·master·Indexed 22 days ago
https://github.com/castorini/anseriniA toolkit built on top of Apache Lucene designed for reproducible information retrieval (IR) research. Anserini provides tools for indexing custom collections in MS MARCO JSONL format and performing retrieval, with a Python interface available via Pyserini. The toolkit supports Lucene 10.4.0 (v2.0.0) and maintains readability for Lucene 9 indexes.
What's inside Anserini
- The Anserini Regressions Log tracks changes to regression tests that affect retrieval effectiveness. It documents when new regression tests are added, when existing ones are removed, and when effectiveness numbers are updated due to changes in underlying components (like analyzers or model implementations). Developers can use this log to investigate why retrieval results or effectiveness metrics have changed over time in the project.
How retrieval systems are evaluated
masterTo measure the quality of a retrieval system, you compare its output against relevance judgments (also known as qrels).
Relevance Judgments (qrels): These are artifacts that map queries to documents with a relevance score. They are typically represented as triples:
[query_id] [document_id] [relevance_score]Example format:
q1 doc23 0 q1 doc452 1 q1 doc536 0 q2 doc97 0(In this example,
doc452is relevant toq1, whiledoc23anddoc536are not).Metrics: Metrics quantify the 'goodness' of a ranked list. A common example is Precision at 10 (P@10), which calculates the fraction of the top 10 documents that are relevant according to the qrels. The final system performance is typically the average of these scores across all queries.
Add metadata to ONNX models for optimization
masterTo facilitate the optimization process, metadata (such as
model_type,num_heads, andhidden_size) should be embedded into the ONNX model. This is done by loading the exported ONNX model and adding properties tometadata_propsbefore saving.# Example of adding metadata to an ONNX model model_type = model.config.model_type num_heads = model.config.num_attention_heads hidden_size = model.config.hidden_size onnx_model = onnx.load(onnx_path) meta = onnx_model.metadata_props.add() meta.key, meta.value = 'model_type', model_type meta = onnx_model.metadata_props.add() meta.key, meta.value = 'num_heads', str(num_heads) meta = onnx_model.metadata_props.add() meta.key, meta.value = 'hidden_size', str(hidden_size) onnx.save(onnx_model, onnx_path)Lucene version compatibility and index readability
masterAnserini was upgraded to Lucene 10.4.0 as part of v2.0.0.
- Lucene 9 indexes: Remain readable by Anserini.
- Lucene 10 indexes: Older versions of Anserini code are unable to read indexes generated by Lucene 10.
Reproduce experiments from document collections
masterAnserini provides an end-to-end framework for reproduction experiments via the
io.anserini.reproduce.ReproduceFromDocumentCollectiondriver. This driver automates the entire pipeline from raw data to evaluated results.When running a reproduction, the driver performs these steps in order:
- Build the index: Constructs the index from scratch using the raw document collection.
- Verify index statistics: Performs a sanity check to ensure the index was built correctly.
- Perform retrieval runs: Executes searches using various settings.
- Evaluate runs: Evaluates the effectiveness of the retrieval runs and verifies the results.
Documentation pages for these experiments are automatically generated from templates located in
src/main/resources/reproduce/from-document-collection/docgen.bin/run.sh io.anserini.reproduce.ReproduceFromDocumentCollection --index --verify --search --config cacmUnderstand SourceDocument parsing logic (contents vs raw)
masterIn Anserini, the
SourceDocumentclass distinguishes betweenraw()andcontents()to ensure collections handle their own parsing logic:raw(): Returns the raw JSON data of the document.contents(): Returns the extracted, parsed content (e.g., article text) intended for indexing.
This separation ensures that 'empty document checks' are performed on the actual parsed content rather than the JSON wrapper, providing a more accurate count of valid documents. When implementing or extending collections, ensure parsing logic resides within the collection implementation to satisfy this principle.
Important: Elastirini is deprecated
master⚠️ Note: Support for Solr integration (Elastirini) was removed in Anserini on August 2, 2022 (commit272565). The features described in this documentation are no longer available. This guide is retained for historical purposes only.Note on Lucene version impact on effectiveness
masterAnserini was upgraded to Lucene 7 in commite71df7aee42c7776a63b9845600a4075632fa11c. This upgrade changes the retrieval results compared to the previous Lucene 6 version. When comparing effectiveness metrics (like AP, NDCG, or P10) against official TREC runs or older reproductions, ensure you are aware of which Lucene version the Anserini build is using, as it directly impacts the scores.How SpladeExportWrapper handles output conversion
masterThe
SpladeExportWrapperis a PyTorchnn.Moduleused during the conversion process to add a 'layer' of logic that transforms raw model outputs into sparse vectors compatible with Anserini.It performs the following steps in its
forwardpass:- Passes
input_idsandattention_maskto the underlying SPLADE model. - Applies
ReLUandlog1pto the logits. - Multiplies the result by the
attention_maskto zero out padding. - Uses
torch.maxacross the sequence dimension to produce a sparse vector. - Returns the non-zero indices and their corresponding values.
class SpladeExportWrapper(nn.Module): def __init__(self, splade_model): super().__init__() self.splade = splade_model def forward(self, input_ids, attention_mask, token_type_ids): # Use token_type_ids in a no-op way to force ONNX to retain it dummy = token_type_ids.sum() * 0.0 outputs = self.splade(input_ids=input_ids, attention_mask=attention_mask) logits = outputs.logits relu = torch.relu(logits) log1p = torch.log1p(relu) sparse_vec = torch.max(log1p * attention_mask.unsqueeze(-1), dim=1).values nonzero = sparse_vec.nonzero(as_tuple=True) values = sparse_vec[nonzero] return nonzero[1], values + dummy- Passes
Understand MS MARCO data formats
masterWhen working with MS MARCO in Anserini, the following data structures are used:
Collection (
collection.tsvor JSONL)- TSV format: Two columns:
docid(unique identifier) and the passage text. - JSONL format: One JSON object per line, used by Anserini for indexing.
Queries (
queries.tsv)- Two columns:
qid(unique query identifier) and the query text.
Relevance Judgments (
qrels.tsv)Standard format for relevance judgments:
qid: Query identifier.0: Historical artifact (almost always 0).docid: Document/passage identifier.relevance: The judgment (e.g.,0for not relevant,1for relevant).
- TSV format: Two columns:
Core concepts of the retrieval problem
masterIn information retrieval (search), the goal is to solve the retrieval problem: given an information need expressed as a query ($q$), return a ranked list of $k$ documents ($d_1, d_2, ext{...}, d_k$) from a finite collection (or corpus) $C$ that maximizes a specific metric (e.g., nDCG, AP).
Key components include:
- Query: The input to the retrieval system representing the user's information need.
- Collection/Corpus: The set of documents being searched.
- Document: A discrete information object (webpage, PDF, passage, etc.) identified by a unique ID.
- Relevance: The relationship between a query and a document (e.g., does this document contain the information sought?). Relevance can be binary (relevant/not relevant) or graded (e.g., a Likert scale).
Reproduce experimental results from prebuilt indexes
masterTo reproduce experimental results using existing prebuilt indexes, refer to the guide indocs/ref-reproduce-from-prebuilt-indexes.md.