Skip to content

FlashRank

rankify.models.flashrank

HF_PRE_DEFIND_MODELS = {'upr': {'t5-small': 'google/t5-small-lm-adapt', 't5-base': 'google/t5-base-lm-adapt', 't5-large': 'google/t5-large-lm-adapt', 't0-3b': 'bigscience/T0_3B', 't0-11b': 'bigscience/T0', 'gpt-neo-2.7b': 'EleutherAI/gpt-neo-2.7B', 'gpt-j-6b': 'EleutherAI/gpt-j-6b', 'gpt2': 'openai-community/gpt2', 'gpt2-medium': 'openai-community/gpt2-medium', 'gpt2-large': 'openai-community/gpt2-large', 'gpt2-xl': 'openai-community/gpt2-xl', 'flan-t5-xl': 'google/flan-t5-xl'}, 'rankgpt-api': {'gpt-3.5': 'gpt-3.5', 'gpt-4': 'gpt-4o', 'gpt-4-mini': 'gpt-4o-mini', 'llamav3.1-8b': 'llamav3.1-8b', 'llamav3.1-70b': 'llamav3.1-70b', 'claude-3-5': 'claude-3-5'}, 'rankgpt': {'llamav3.1-8b': 'meta-llama/Meta-Llama-3.1-8B-Instruct', 'llamav3.1-70b': 'meta-llama/Llama-3.1-70B-Instruct', 'Llama-3.2-1B': 'meta-llama/Llama-3.2-1B-Instruct', 'Llama-3.2-3B': 'meta-llama/Llama-3.2-3B-Instruct', 'Qwen2.5-7B': 'Qwen/Qwen2.5-7B', 'Mistral-7B-Instruct-v0.2': 'mistralai/Mistral-7B-Instruct-v0.2', 'Mistral-7B-Instruct-v0.3': 'mistralai/Mistral-7B-Instruct-v0.3'}, 'flashrank': {'ms-marco-TinyBERT-L-2-v2': 'ms-marco-TinyBERT-L-2-v2', 'ms-marco-MiniLM-L-12-v2': 'ms-marco-MiniLM-L-12-v2', 'ms-marco-MultiBERT-L-12': 'ms-marco-MultiBERT-L-12', 'rank-T5-flan': 'rank-T5-flan', 'ce-esci-MiniLM-L12-v2': 'ce-esci-MiniLM-L12-v2', 'rank_zephyr_7b_v1_full': 'rank_zephyr_7b_v1_full', 'miniReranker_arabic_v1': 'miniReranker_arabic_v1'}, 'flashrank-model-file': {'ms-marco-TinyBERT-L-2-v2': 'flashrank-TinyBERT-L-2-v2.onnx', 'ms-marco-MiniLM-L-12-v2': 'flashrank-MiniLM-L-12-v2_Q.onnx', 'ms-marco-MultiBERT-L-12': 'flashrank-MultiBERT-L12_Q.onnx', 'rank-T5-flan': 'flashrank-rankt5_Q.onnx', 'ce-esci-MiniLM-L12-v2': 'flashrank-ce-esci-MiniLM-L12-v2_Q.onnx', 'rank_zephyr_7b_v1_full': 'rank_zephyr_7b_v1_full.Q4_K_M.gguf', 'miniReranker_arabic_v1': 'miniReranker_arabic_v1.onnx'}, 'monot5': {'monot5-base-msmarco': 'castorini/monot5-base-msmarco', 'monot5-base-msmarco-10k': 'castorini/monot5-base-msmarco-10k', 'monot5-large-msmarco': 'castorini/monot5-large-msmarco', 'monot5-large-msmarco-10k': 'castorini/monot5-large-msmarco-10k', 'monot5-base-med-msmarco': 'castorini/monot5-base-med-msmarco', 'monot5-3b-med-msmarco': 'castorini/monot5-3b-med-msmarco', 'monot5-3b-msmarco-10k': 'castorini/monot5-3b-msmarco-10k', 'mt5-base-en-msmarco': 'unicamp-dl/mt5-base-en-msmarco', 'ptt5-base-pt-msmarco-10k-v2': 'unicamp-dl/ptt5-base-pt-msmarco-10k-v2', 'ptt5-base-pt-msmarco-100k-v2': 'unicamp-dl/ptt5-base-pt-msmarco-100k-v2', 'ptt5-base-en-pt-msmarco-100k-v2': 'unicamp-dl/ptt5-base-en-pt-msmarco-100k-v2', 'mt5-base-en-pt-msmarco-v2': 'unicamp-dl/mt5-base-en-pt-msmarco-v2', 'mt5-base-mmarco-v2': 'unicamp-dl/mt5-base-mmarco-v2', 'mt5-base-en-pt-msmarco-v1': 'unicamp-dl/mt5-base-en-pt-msmarco-v1', 'mt5-base-mmarco-v1': 'unicamp-dl/mt5-base-mmarco-v1', 'ptt5-base-pt-msmarco-10k-v1': 'unicamp-dl/ptt5-base-pt-msmarco-10k-v1', 'ptt5-base-pt-msmarco-100k-v1': 'unicamp-dl/ptt5-base-pt-msmarco-100k-v1', 'ptt5-base-en-pt-msmarco-10k-v1': 'unicamp-dl/ptt5-base-en-pt-msmarco-10k-v1', 'mt5-3B-mmarco-en-pt': 'unicamp-dl/mt5-3B-mmarco-en-pt', 'mt5-13b-mmarco-100k': 'unicamp-dl/mt5-13b-mmarco-100k', 'monoptt5-small': 'unicamp-dl/monoptt5-small', 'monoptt5-base': 'unicamp-dl/monoptt5-base', 'monoptt5-large': 'unicamp-dl/monoptt5-large', 'monoptt5-3b': 'unicamp-dl/monoptt5-3b'}, 'rankt5': {'rankt5-base': 'Soyoung97/RankT5-base', 'rankt5-large': 'Soyoung97/RankT5-large', 'rankt5-3b': 'Soyoung97/RankT5-3b'}, 'listt5': {'listt5-base': 'Soyoung97/ListT5-base', 'listt5-3b': 'Soyoung97/ListT5-3b'}, 'inranker': {'inranker-small': 'unicamp-dl/InRanker-small', 'inranker-base': 'unicamp-dl/InRanker-base', 'inranker-3b': 'unicamp-dl/InRanker-3B'}, 'apiranker': {'cohere': 'cohere', 'jina': 'jina', 'voyage': 'voyage', 'mixedbread.ai': 'mixedbread.ai'}, 'transformer_ranker': {'mxbai-rerank-xsmall': 'mixedbread-ai/mxbai-rerank-xsmall-v1', 'mxbai-rerank-base': 'mixedbread-ai/mxbai-rerank-base-v1', 'mxbai-rerank-large': 'mixedbread-ai/mxbai-rerank-large-v1', 'bge-reranker-base': 'BAAI/bge-reranker-base', 'bge-reranker-large': 'BAAI/bge-reranker-large', 'bge-reranker-v2-m3': 'BAAI/bge-reranker-v2-m3', 'bce-reranker-base': 'maidalun1020/bce-reranker-base_v1', 'jina-reranker-tiny': 'jinaai/jina-reranker-v1-tiny-en', 'jina-reranker-turbo': 'jinaai/jina-reranker-v1-turbo-en', 'jina-reranker-base-multilingual': 'jinaai/jina-reranker-v2-base-multilingual', 'gte-multilingual-reranker-base': 'Alibaba-NLP/gte-multilingual-reranker-base', 'camembert-base-mmarcoFR': 'antoinelouis/crossencoder-camembert-base-mmarcoFR', 'camembert-large-mmarcoFR': 'antoinelouis/crossencoder-camembert-large-mmarcoFR', 'camemberta-base-mmarcoFR': 'antoinelouis/crossencoder-camemberta-base-mmarcoFR', 'distilcamembert-mmarcoFR': 'antoinelouis/crossencoder-distilcamembert-mmarcoFR', 'cross-encoder-mmarco-mMiniLMv2-L12-H384-v1': 'corrius/cross-encoder-mmarco-mMiniLMv2-L12-H384-v1', 'nli-deberta-v3-large': 'cross-encoder/nli-deberta-v3-large', 'ms-marco-MiniLM-L-12-v2': 'cross-encoder/ms-marco-MiniLM-L-12-v2', 'ms-marco-MiniLM-L-6-v2': 'cross-encoder/ms-marco-MiniLM-L-6-v2', 'ms-marco-MiniLM-L-4-v2': 'cross-encoder/ms-marco-MiniLM-L-4-v2', 'ms-marco-MiniLM-L-2-v2': 'cross-encoder/ms-marco-MiniLM-L-2-v2', 'ms-marco-TinyBERT-L-2-v2': 'cross-encoder/ms-marco-TinyBERT-L-2-v2', 'ms-marco-electra-base': 'cross-encoder/ms-marco-electra-base', 'ms-marco-TinyBERT-L-6': 'cross-encoder/ms-marco-TinyBERT-L-6', 'ms-marco-TinyBERT-L-4': 'cross-encoder/ms-marco-TinyBERT-L-4', 'ms-marco-TinyBERT-L-2': 'cross-encoder/ms-marco-TinyBERT-L-2', 'msmarco-MiniLM-L12-en-de-v1': 'cross-encoder/msmarco-MiniLM-L12-en-de-v1', 'msmarco-MiniLM-L6-en-de-v1': 'cross-encoder/msmarco-MiniLM-L6-en-de-v1'}, 'llm_layerwise_ranker': {'bge-multilingual-gemma2': 'BAAI/bge-multilingual-gemma2', 'bge-reranker-v2-gemma': 'BAAI/bge-reranker-v2-gemma', 'bge-reranker-v2-minicpm-layerwise': 'BAAI/bge-reranker-v2-minicpm-layerwise', 'bge-reranker-v2.5-gemma2-lightweight': 'BAAI/bge-reranker-v2.5-gemma2-lightweight'}, 'first_ranker': {'First-Model': 'rryisthebest/First_Model', 'Llama-3-8B': 'meta-llama/Meta-Llama-3-8B-Instruct'}, 'lit5dist': {'LiT5-Distill-base': 'castorini/LiT5-Distill-base', 'LiT5-Distill-large': 'castorini/LiT5-Distill-large', 'LiT5-Distill-xl': 'castorini/LiT5-Distill-xl', 'LiT5-Distill-base-v2': 'castorini/LiT5-Distill-base-v2', 'LiT5-Distill-large-v2': 'castorini/LiT5-Distill-large-v2', 'LiT5-Distill-xl-v2': 'castorini/LiT5-Distill-xl-v2'}, 'lit5score': {'LiT5-Score-base': 'castorini/LiT5-Score-base', 'LiT5-Score-large': 'castorini/LiT5-Score-large', 'LiT5-Score-xl': 'castorini/LiT5-Score-xl'}, 'vicuna_reranker': {'rank_vicuna_7b_v1': 'castorini/rank_vicuna_7b_v1', 'rank_vicuna_7b_v1_noda': 'castorini/rank_vicuna_7b_v1_noda', 'rank_vicuna_7b_v1_fp16': 'castorini/rank_vicuna_7b_v1_fp16', 'rank_vicuna_7b_v1_noda_fp16': 'castorini/rank_vicuna_7b_v1_noda_fp16'}, 'zephyr_reranker': {'rank_zephyr_7b_v1_full': 'castorini/rank_zephyr_7b_v1_full'}, 'blender_reranker': {'PairRM': 'llm-blender/PairRM'}, 'splade_reranker': {'splade-cocondenser': 'naver/splade-cocondenser-ensembledistil'}, 'sentence_transformer_reranker': {'all-MiniLM-L6-v2': 'all-MiniLM-L6-v2', 'gtr-t5-base': 'sentence-transformers/gtr-t5-base', 'gtr-t5-large': 'sentence-transformers/gtr-t5-large', 'gtr-t5-xl': 'sentence-transformers/gtr-t5-xl', 'gtr-t5-xxl': 'sentence-transformers/gtr-t5-xxl', 'sentence-t5-base': 'sentence-transformers/sentence-t5-base', 'sentence-t5-xl': 'sentence-transformers/sentence-t5-xl', 'sentence-t5-xxl': 'sentence-transformers/sentence-t5-xxl', 'sentence-t5-large': 'sentence-transformers/sentence-t5-large', 'distilbert-multilingual-nli-stsb-quora-ranking': 'sentence-transformers/distilbert-multilingual-nli-stsb-quora-ranking', 'msmarco-bert-co-condensor': 'sentence-transformers/msmarco-bert-co-condensor', 'msmarco-roberta-base-v2': 'sentence-transformers/msmarco-roberta-base-v2'}, 'colbert_ranker': {'colbertv2.0': 'colbert-ir/colbertv2.0', 'FranchColBERT': 'bclavie/FraColBERTv2', 'JapanColBERT': 'bclavie/JaColBERTv2', 'SpanishColBERT': 'AdrienB134/ColBERTv2.0-spanish-mmarcoES', 'jina-colbert-v1-en': 'jinaai/jina-colbert-v1-en', 'ArabicColBERT-250k': 'akhooli/arabic-colbertv2-250k-norm', 'ArabicColBERT-711k': 'akhooli/arabic-colbertv2-711k-norm', 'BengaliColBERT': 'turjo4nis/colbertv2.0-bn', 'mxbai-colbert-large-v1': 'mixedbread-ai/mxbai-colbert-large-v1'}, 'monobert': {'monobert-large': 'castorini/monobert-large-msmarco'}, 'llm2vec': {'Meta-Llama-31-8B': 'McGill-NLP/LLM2Vec-Meta-Llama-31-8B-Instruct-mntp', 'Meta-Llama-3-8B': 'McGill-NLP/LLM2Vec-Meta-Llama-3-8B-Instruct-mntp', 'Mistral-7B': 'McGill-NLP/LLM2Vec-Mistral-7B-Instruct-v2-mntp', 'Llama-2-7B': 'McGill-NLP/LLM2Vec-Llama-2-7b-chat-hf-mntp', 'Sheared-LLaMA': 'McGill-NLP/LLM2Vec-Sheared-LLaMA-mntp'}, 'twolar': {'twolar-xl': 'Dundalia/TWOLAR-xl', 'twolar-large': 'Dundalia/TWOLAR-large'}, 'duot5': {'duot5-base-msmarco': 'castorini/duot5-base-msmarco', 'duot5-3b-msmarco': 'castorini/duot5-3b-msmarco', 'duot5-large-msmarco': 'castorini/duot5-large-msmarco-10k'}, 'rankllama': {'rankllama-v1-7b-lora-passage': 'castorini/rankllama-v1-7b-lora-passage'}, 'dear_reranker': {'dear-3b-reranker-ce-v1': 'abdoelsayed/dear-3b-reranker-ce-v1', 'dear-3b-reranker-ranknet-v1': 'abdoelsayed/dear-3b-reranker-ranknet-v1', 'dear-3b-reranker-ce-lora-v1': 'abdoelsayed/dear-3b-reranker-ce-lora-v1', 'dear-8b-reranker-ce-v1': 'abdoelsayed/dear-8b-reranker-ce-v1'}, 'echorank': {'flan-t5-large': 'google/flan-t5-large', 'flan-t5-xl': 'google/flan-t5-xl'}, 'incontext_reranker': {'llamav3.1-8b': 'meta-llama/Meta-Llama-3.1-8B-Instruct', 'llamav3.1-70b': 'meta-llama/Llama-3.1-70B-Instruct', 'Mistral-7B-Instruct-v0.2': 'mistralai/Mistral-7B-Instruct-v0.2'}, 'tart': {'tart-full-flan-t5-xl': 'facebook/tart-full-flan-t5-xl', 'tart-dual-flan-t5-xl': 'facebook/tart-dual-flan-t5-xl'}, 'prp': {'llamav3.1-8b': 'meta-llama/Meta-Llama-3.1-8B-Instruct', 'llamav3.1-70b': 'meta-llama/Llama-3.1-70B-Instruct', 'Llama-3.2-1B': 'meta-llama/Llama-3.2-1B-Instruct', 'Llama-3.2-3B': 'meta-llama/Llama-3.2-3B-Instruct', 'Mistral-7B-Instruct-v0.3': 'mistralai/Mistral-7B-Instruct-v0.3'}, 'prp-api': {'gpt-3.5': 'gpt-3.5-turbo', 'gpt-4': 'gpt-4o', 'gpt-4-mini': 'gpt-4o-mini', 'llamav3.1-8b': 'llamav3.1-8b', 'llamav3.1-70b': 'llamav3.1-70b'}, 'rankgemma': {'gemma-2-2b': 'google/gemma-2-2b-it', 'gemma-2-9b': 'google/gemma-2-9b-it', 'gemma-2-27b': 'google/gemma-2-27b-it'}, 'rankmistral': {'mistral-7b': 'mistralai/Mistral-7B-Instruct-v0.3', 'mistral-7b-v0.2': 'mistralai/Mistral-7B-Instruct-v0.2', 'mixtral-8x7b': 'mistralai/Mixtral-8x7B-Instruct-v0.1'}} module-attribute

Document

Represents a document consisting of a question, answers, and contexts.

Attributes:

Name Type Description
question Question

The question associated with the document.

answers Answer

The answers to the question.

contexts list[Context]

A list of related contexts.

reorder_contexts list[Context] or None

A reordered list of contexts based on relevance.

Source code in rankify/dataset/dataset.py
class Document:
    """
    Represents a document consisting of a question, answers, and contexts.

    Attributes:
        question (Question): The question associated with the document.
        answers (Answer): The answers to the question.
        contexts (list[Context]): A list of related contexts.
        reorder_contexts (list[Context] or None): A reordered list of contexts based on relevance.
    """
    def __init__(self, question: Question, answers: Answer, contexts: list = None , id: int = None) -> None:
        """
        Initializes a Document instance.

        Args:
            question (Question): The question associated with the document.
            answers (Answer): The answers to the question.
            contexts (list[Context], optional): A list of contexts related to the question.

        Example:
            ```python
            q = Question("What is the capital of France?")
            a = Answer(["Paris"])
            c1 = Context(score=0.9, has_answer=True, id=1, title="Paris", text="The capital of France is Paris.")
            c2 = Context(score=0.5, has_answer=False, id=2, title="Berlin", text="Berlin is the capital of Germany.")
            d = Document(question=q, answers=a, contexts=[c1, c2])
            print(d)
            ```
        """
        self.question: Question = question
        self.answers: Answer = answers
        self.contexts: List[Context] = contexts
        self.reorder_contexts: List[Context] = None
        self.id = str(id) 

    @classmethod
    def from_dict(cls, data: dict,n_docs:int=100) -> 'Document':
        """
        Creates a Document instance from a dictionary.

        Args:
            data (dict): A dictionary containing the question, answers, and contexts.
            n_docs (int, optional): The number of contexts to include. Defaults to 100.

        Returns:
            Document: A new Document instance.

        Example:
            ```python
            data = {
                "question": "What is the capital of France?",
                "answers": ["Paris"],
                "ctxs": [
                    {"score": 0.9, "has_answer": True, "id": 1, "title": "Paris", "text": "The capital of France is Paris."},
                    {"score": 0.5, "has_answer": False, "id": 2, "title": "Berlin", "text": "Berlin is the capital of Germany."}
                ]
            }
            d = Document.from_dict(data)
            print(d.question)
            ```
        """
        question = Question(data["question"])
        if "answers" in data:
            answers = Answer(data["answers"])
        else:
            answers =Answer('')

        if "query_id" in data:
            id = data["query_id"]
        else:
            id = None
        contexts = [Context(**ctx) for ctx in data["ctxs"][:n_docs]]
        return cls(question, answers, contexts, id=id)

    def to_dict(self) -> Dict[str, Optional[object]]:
        """
        Converts the document into a dictionary representation.

        Returns:
            dict: A dictionary containing the question, answers, and contexts.
        """
        return {
            "question": self.question.question,
            "answers": self.answers.answers,
            "contexts": [ctx.to_dict() for ctx in self.contexts]
        }
    def to_dict_reoreder(self) -> Dict[str,Optional[object]]:
        return {
            "question" : self.question.question,
            "answers" : self.answers.answers,
            "contexts" : [ctx.to_dict() for ctx in self.reorder_contexts]
        }
    def __str__(self) -> str:
        """
        Returns a string representation of the Document instance.

        Returns:
            str: The formatted document information.

        Example:
            ```python
            d = Document(Question("What is the capital of France?"), Answer(["Paris"]))
            print(d)
            ```
        """
        contexts_str = "\n\n".join([str(ctx) for ctx in self.contexts])
        reorder_contexts_str= ''
        if self.reorder_contexts is not None:
            reorder_contexts_str = "\n\n".join([str(ctx) for ctx in self.reorder_contexts])
        return f"{self.question}\n\n{self.answers}\n\nContext: \n\n{contexts_str}\nReorder contexts: \n\n{reorder_contexts_str}"

__init__(question, answers, contexts=None, id=None)

Initializes a Document instance.

Parameters:

Name Type Description Default
question Question

The question associated with the document.

required
answers Answer

The answers to the question.

required
contexts list[Context]

A list of contexts related to the question.

None
Example
q = Question("What is the capital of France?")
a = Answer(["Paris"])
c1 = Context(score=0.9, has_answer=True, id=1, title="Paris", text="The capital of France is Paris.")
c2 = Context(score=0.5, has_answer=False, id=2, title="Berlin", text="Berlin is the capital of Germany.")
d = Document(question=q, answers=a, contexts=[c1, c2])
print(d)
Source code in rankify/dataset/dataset.py
def __init__(self, question: Question, answers: Answer, contexts: list = None , id: int = None) -> None:
    """
    Initializes a Document instance.

    Args:
        question (Question): The question associated with the document.
        answers (Answer): The answers to the question.
        contexts (list[Context], optional): A list of contexts related to the question.

    Example:
        ```python
        q = Question("What is the capital of France?")
        a = Answer(["Paris"])
        c1 = Context(score=0.9, has_answer=True, id=1, title="Paris", text="The capital of France is Paris.")
        c2 = Context(score=0.5, has_answer=False, id=2, title="Berlin", text="Berlin is the capital of Germany.")
        d = Document(question=q, answers=a, contexts=[c1, c2])
        print(d)
        ```
    """
    self.question: Question = question
    self.answers: Answer = answers
    self.contexts: List[Context] = contexts
    self.reorder_contexts: List[Context] = None
    self.id = str(id) 

from_dict(data, n_docs=100) classmethod

Creates a Document instance from a dictionary.

Parameters:

Name Type Description Default
data dict

A dictionary containing the question, answers, and contexts.

required
n_docs int

The number of contexts to include. Defaults to 100.

100

Returns:

Name Type Description
Document Document

A new Document instance.

Example
data = {
    "question": "What is the capital of France?",
    "answers": ["Paris"],
    "ctxs": [
        {"score": 0.9, "has_answer": True, "id": 1, "title": "Paris", "text": "The capital of France is Paris."},
        {"score": 0.5, "has_answer": False, "id": 2, "title": "Berlin", "text": "Berlin is the capital of Germany."}
    ]
}
d = Document.from_dict(data)
print(d.question)
Source code in rankify/dataset/dataset.py
@classmethod
def from_dict(cls, data: dict,n_docs:int=100) -> 'Document':
    """
    Creates a Document instance from a dictionary.

    Args:
        data (dict): A dictionary containing the question, answers, and contexts.
        n_docs (int, optional): The number of contexts to include. Defaults to 100.

    Returns:
        Document: A new Document instance.

    Example:
        ```python
        data = {
            "question": "What is the capital of France?",
            "answers": ["Paris"],
            "ctxs": [
                {"score": 0.9, "has_answer": True, "id": 1, "title": "Paris", "text": "The capital of France is Paris."},
                {"score": 0.5, "has_answer": False, "id": 2, "title": "Berlin", "text": "Berlin is the capital of Germany."}
            ]
        }
        d = Document.from_dict(data)
        print(d.question)
        ```
    """
    question = Question(data["question"])
    if "answers" in data:
        answers = Answer(data["answers"])
    else:
        answers =Answer('')

    if "query_id" in data:
        id = data["query_id"]
    else:
        id = None
    contexts = [Context(**ctx) for ctx in data["ctxs"][:n_docs]]
    return cls(question, answers, contexts, id=id)

to_dict()

Converts the document into a dictionary representation.

Returns:

Name Type Description
dict Dict[str, Optional[object]]

A dictionary containing the question, answers, and contexts.

Source code in rankify/dataset/dataset.py
def to_dict(self) -> Dict[str, Optional[object]]:
    """
    Converts the document into a dictionary representation.

    Returns:
        dict: A dictionary containing the question, answers, and contexts.
    """
    return {
        "question": self.question.question,
        "answers": self.answers.answers,
        "contexts": [ctx.to_dict() for ctx in self.contexts]
    }

__str__()

Returns a string representation of the Document instance.

Returns:

Name Type Description
str str

The formatted document information.

Example
d = Document(Question("What is the capital of France?"), Answer(["Paris"]))
print(d)
Source code in rankify/dataset/dataset.py
def __str__(self) -> str:
    """
    Returns a string representation of the Document instance.

    Returns:
        str: The formatted document information.

    Example:
        ```python
        d = Document(Question("What is the capital of France?"), Answer(["Paris"]))
        print(d)
        ```
    """
    contexts_str = "\n\n".join([str(ctx) for ctx in self.contexts])
    reorder_contexts_str= ''
    if self.reorder_contexts is not None:
        reorder_contexts_str = "\n\n".join([str(ctx) for ctx in self.reorder_contexts])
    return f"{self.question}\n\n{self.answers}\n\nContext: \n\n{contexts_str}\nReorder contexts: \n\n{reorder_contexts_str}"

BaseRanking

Bases: ABC

An abstract base class for implementing different ranking models.

This class defines the interface for all ranking models, ensuring that all subclasses implement the required methods.

Attributes:

Name Type Description
method str

The name of the ranking method.

model_name str

The name of the model being used for ranking.

api_key str

An optional API key for accessing remote models or services.

Source code in rankify/models/base.py
class BaseRanking(ABC):
    """
    An abstract base class for implementing different ranking models.

    This class defines the interface for all ranking models, ensuring that all subclasses implement the required methods.

    Attributes:
        method (str): The name of the ranking method.
        model_name (str): The name of the model being used for ranking.
        api_key (str, optional): An optional API key for accessing remote models or services.
    """

    @abstractmethod
    def __init__(self, method: str= None, model_name: str= None, api_key: str= None, **kwargs) ->None:
        """
        Initializes the base ranking model.

        Args:
            method (str, optional): The name of the ranking method. Defaults to None.
            model_name (str, optional): The name of the model being used for ranking. Defaults to None.
            api_key (str, optional): An optional API key for accessing remote models or services. Defaults to None.

        Example:
            ```python
            class MyRanking(BaseRanking):
                def __init__(self, method, model_name):
                    super().__init__(method, model_name)
            ```
        """
        pass

    @abstractmethod
    def rank(self, documents: list[Document] ):
        """
        Abstract method to rank a list of documents.

        Args:
            documents (list[Document]): A list of Document instances that need to be ranked.

        Raises:
            NotImplementedError: This method must be implemented by subclasses.

        Example:
            ```python
            class MyRanking(BaseRanking):
                def __init__(self, method, model_name):
                    super().__init__(method, model_name)

                def rank(self, documents):
                    # Ranking implementation here
                    pass
            ```
        """
        pass

__init__(method=None, model_name=None, api_key=None, **kwargs) abstractmethod

Initializes the base ranking model.

Parameters:

Name Type Description Default
method str

The name of the ranking method. Defaults to None.

None
model_name str

The name of the model being used for ranking. Defaults to None.

None
api_key str

An optional API key for accessing remote models or services. Defaults to None.

None
Example
class MyRanking(BaseRanking):
    def __init__(self, method, model_name):
        super().__init__(method, model_name)
Source code in rankify/models/base.py
@abstractmethod
def __init__(self, method: str= None, model_name: str= None, api_key: str= None, **kwargs) ->None:
    """
    Initializes the base ranking model.

    Args:
        method (str, optional): The name of the ranking method. Defaults to None.
        model_name (str, optional): The name of the model being used for ranking. Defaults to None.
        api_key (str, optional): An optional API key for accessing remote models or services. Defaults to None.

    Example:
        ```python
        class MyRanking(BaseRanking):
            def __init__(self, method, model_name):
                super().__init__(method, model_name)
        ```
    """
    pass

rank(documents) abstractmethod

Abstract method to rank a list of documents.

Parameters:

Name Type Description Default
documents list[Document]

A list of Document instances that need to be ranked.

required

Raises:

Type Description
NotImplementedError

This method must be implemented by subclasses.

Example
class MyRanking(BaseRanking):
    def __init__(self, method, model_name):
        super().__init__(method, model_name)

    def rank(self, documents):
        # Ranking implementation here
        pass
Source code in rankify/models/base.py
@abstractmethod
def rank(self, documents: list[Document] ):
    """
    Abstract method to rank a list of documents.

    Args:
        documents (list[Document]): A list of Document instances that need to be ranked.

    Raises:
        NotImplementedError: This method must be implemented by subclasses.

    Example:
        ```python
        class MyRanking(BaseRanking):
            def __init__(self, method, model_name):
                super().__init__(method, model_name)

            def rank(self, documents):
                # Ranking implementation here
                pass
        ```
    """
    pass

FlashRanker

Bases: BaseRanking

Implements FlashRank, a fast and efficient reranking model supporting pairwise cross-encoding (ONNX) and listwise ranking with LLMs (GGUF models).

FlashRank efficiently reranks passages for a given query using either: - ONNX-based pairwise reranking (cross-encoder) for fast inference. - LLM-based listwise reranking using RankGPT.

This method is optimized for speed and accuracy while maintaining scalability.

Attributes:

Name Type Description
method str

The reranking method name.

model_name str

The name of the model used for reranking.

api_key str

API key for accessing remote models (if applicable).

cache_dir Path

Directory where models are cached.

model_dir Path

Directory containing the specific model.

session InferenceSession

The ONNX runtime session for inference (used for pairwise reranking).

tokenizer Tokenizer

The tokenizer for text processing.

llm_model Llama

If using an LLM-based reranker, this holds the model instance.

References
  • Damodaran, P. (2023). FlashRank, Lightest and Fastest 2nd Stage Reranker for search pipelines.
    Paper

Examples:

from rankify.dataset.dataset import Document, Question, Answer, Context
from rankify.models.reranking import Reranking

question = Question("What is the capital of France?")
answers = Answer(["Paris is the capital of France."])
contexts = [
    Context(text="Berlin is the capital of Germany.", id=0),
    Context(text="Paris is the capital of France.", id=1),
    Context(text="Madrid is the capital of Spain.", id=2),
]
document = Document(question=question, answers=answers, contexts=contexts)

# Initialize Reranking with FlashRanker
model = Reranking(method="flashrank", model_name="ms-marco-TinyBERT-L-2-v2")
model.rank([document])

# Print reordered contexts
print("Reordered Contexts:")
for context in document.reorder_contexts:
    print(context.text)
Notes
  • FlashRank supports ONNX models for cross-encoder-based reranking.
  • LLM-based reranking is supported using GGUF models.
  • Integrated into the Reranking class, so use Reranking instead of FlashRanker directly.
Source code in rankify/models/flashrank.py
class FlashRanker(BaseRanking):
    """
    Implements FlashRank, a fast and efficient reranking model supporting pairwise cross-encoding (ONNX)
    and listwise ranking with LLMs (GGUF models).

    FlashRank efficiently reranks passages for a given query using either:
    - ONNX-based pairwise reranking (cross-encoder) for fast inference.
    - LLM-based listwise reranking using RankGPT.

    This method is optimized for speed and accuracy while maintaining scalability.

    Attributes:
        method (str): The reranking method name.
        model_name (str): The name of the model used for reranking.
        api_key (str, optional): API key for accessing remote models (if applicable).
        cache_dir (Path): Directory where models are cached.
        model_dir (Path): Directory containing the specific model.
        session (ort.InferenceSession, optional): The ONNX runtime session for inference (used for pairwise reranking).
        tokenizer (Tokenizer, optional): The tokenizer for text processing.
        llm_model (Llama, optional): If using an LLM-based reranker, this holds the model instance.

    References:
        - Damodaran, P. (2023). FlashRank, Lightest and Fastest 2nd Stage Reranker for search pipelines.  
          [Paper](https://doi.org/10.5281/zenodo.10426927)

    Examples:
        ```python
        from rankify.dataset.dataset import Document, Question, Answer, Context
        from rankify.models.reranking import Reranking

        question = Question("What is the capital of France?")
        answers = Answer(["Paris is the capital of France."])
        contexts = [
            Context(text="Berlin is the capital of Germany.", id=0),
            Context(text="Paris is the capital of France.", id=1),
            Context(text="Madrid is the capital of Spain.", id=2),
        ]
        document = Document(question=question, answers=answers, contexts=contexts)

        # Initialize Reranking with FlashRanker
        model = Reranking(method="flashrank", model_name="ms-marco-TinyBERT-L-2-v2")
        model.rank([document])

        # Print reordered contexts
        print("Reordered Contexts:")
        for context in document.reorder_contexts:
            print(context.text)
        ```

    Notes:
        - FlashRank supports ONNX models for cross-encoder-based reranking.
        - LLM-based reranking is supported using GGUF models.
        - Integrated into the `Reranking` class, so use `Reranking` instead of `FlashRanker` directly.
    """

    def __init__(self, method: str = None, model_name: str = None, api_key: str = None, **kwargs):
        """
        Initializes the FlashRanker model for reranking.

        Args:
            method (str, optional): The reranking method name.
            model_name (str, optional): The name of the reranking model to be used.
            model_dir (str, optional): Path to a custom model directory if the user provides their own model.
            api_key (str, optional): API key for remote access (if applicable).

        Raises:
            ValueError: If an invalid model name is provided or model files are missing.
        """
        max_length: int = 512
        log_level: str = "INFO"

        logging.basicConfig(level=getattr(logging, log_level.upper(), logging.INFO))
        self.logger = logging.getLogger(__name__)
        model_dir = kwargs.get("model_dir", None)
        # Predefined FlashRank models
        available_models = HF_PRE_DEFIND_MODELS['flashrank']

        if model_name:
            if model_name not in available_models:
                raise ValueError(
                    f"Invalid model name '{model_name}'. Choose from: {list(available_models.keys())} or specify a custom model directory."
                )
            model_file = HF_PRE_DEFIND_MODELS['flashrank-model-file'].get(model_name)
        elif model_dir:
            model_name = "custom_model"
            model_file =kwargs.get("model_file")  # User must provide the model file name
            if not model_file:
                raise ValueError("When using a custom model directory, you must specify 'model_dir' and 'model_file'.")

        else:
            raise ValueError("Either 'model_name' or 'model_dir' must be provided.")

        # Set paths
        self.cache_dir: Path = Path(os.environ.get('RERANKING_CACHE_DIR', './cache')) / 'models'
        self.model_dir: Path = Path(model_dir) if model_dir else self.cache_dir / model_name

        # Ensure model directory exists
        if not self.model_dir.exists():
            if model_dir:
                raise FileNotFoundError(f"Custom model directory '{self.model_dir}' not found.")
            self.logger.info(f"Downloading model '{model_name}'...")
            self._download_model_files(model_name)

        listwise_rankers = {'rank_zephyr_7b_v1_full'}
        self.llm_model = None

        if model_name in listwise_rankers:
            try:
                from llama_cpp import Llama
                self.llm_model = Llama(
                    model_path=str(self.model_dir / model_file),
                    n_ctx=max_length,
                    n_threads=8,
                )
            except ImportError:
                raise ImportError("Please install 'pip install flashrank[listwise]' to use listwise rerankers.")

        else:
            self.session = ort.InferenceSession(str(self.model_dir / model_file))
            self.tokenizer: Tokenizer = self._get_tokenizer(max_length)

    def _prepare_model_dir(self, model_name: str):
        """
        Ensures the model directory is prepared by downloading and extracting the model if not present.

        Args:
            model_name (str): The name of the model to be prepared.
        """
        if not self.cache_dir.exists():
            self.logger.debug(f"Cache directory {self.cache_dir} not found. Creating it..")
            self.cache_dir.mkdir(parents=True, exist_ok=True)

        if not self.model_dir.exists():
            self.logger.info(f"Downloading {model_name}...")
            self._download_model_files(model_name)

    def _download_model_files(self, model_name: str):
        """
        Downloads and extracts the model files from a specified URL.

        Args:
            model_name (str): The name of the model to download.
        """
        self.cache_dir.mkdir(parents=True, exist_ok=True)

        local_zip_file = self.cache_dir / f"{model_name}.zip"
        model_url = "https://huggingface.co/prithivida/flashrank/resolve/main/{}.zip"
        formatted_model_url = model_url.format(model_name)

        with requests.get(formatted_model_url, stream=True) as r:
            r.raise_for_status()
            total_size = int(r.headers.get('content-length', 0))
            with open(local_zip_file, 'wb') as f, tqdm(desc=local_zip_file.name, total=total_size, unit='iB', unit_scale=True, unit_divisor=1024) as bar:
                for chunk in r.iter_content(chunk_size=8192):
                    size = f.write(chunk)
                    bar.update(size)

        with zipfile.ZipFile(local_zip_file, 'r') as zip_ref:
            zip_ref.extractall(self.cache_dir)
        os.remove(local_zip_file)

    def _get_tokenizer(self, max_length: int = 512) -> Tokenizer:
        """
        Initializes and configures the tokenizer with padding and truncation.

        Args:
            max_length (int): The maximum token length for truncation.

        Returns:
            Tokenizer: Configured tokenizer for text processing.
        """
        config = json.load(open(str(self.model_dir / "config.json")))
        tokenizer_config = json.load(open(str(self.model_dir / "tokenizer_config.json")))
        tokens_map = json.load(open(str(self.model_dir / "special_tokens_map.json")))
        tokenizer = Tokenizer.from_file(str(self.model_dir / "tokenizer.json"))
        #print(tokenizer_config["model_max_length"] , max_length)
        tokenizer.enable_truncation(max_length=min(tokenizer_config["model_max_length"], max_length))
        tokenizer.enable_padding(pad_id=config["pad_token_id"], pad_token=tokenizer_config["pad_token"])

        for token in tokens_map.values():
            if isinstance(token, str):
                tokenizer.add_special_tokens([token])
            elif isinstance(token, dict):
                tokenizer.add_special_tokens([AddedToken(**token)])

        vocab_file = self.model_dir / "vocab.txt"
        if vocab_file.exists():
            tokenizer.vocab = self._load_vocab(vocab_file)
            tokenizer.ids_to_tokens = collections.OrderedDict([(ids, tok) for tok, ids in tokenizer.vocab.items()])
        return tokenizer

    def _load_vocab(self, vocab_file: Path) -> Dict[str, int]:
        """
        Loads the vocabulary from a file and returns it as an ordered dictionary.

        Args:
            vocab_file (Path): The file path to the vocabulary.

        Returns:
            Dict[str, int]: An ordered dictionary mapping tokens to their respective indices.
        """
        vocab = collections.OrderedDict()
        with open(vocab_file, "r", encoding="utf-8") as reader:
            tokens = reader.readlines()
        for index, token in enumerate(tokens):
            token = token.rstrip("\n")
            vocab[token] = index
        return vocab

    def _get_prefix_prompt(self, query, num):
        """
        Generates the prefix for prompting the LLM.

        Args:
            query (str): The query to rank contexts against.
            num (int): The number of passages to rank.

        Returns:
            List[Dict[str, str]]: The initial ranking prompt.
        """
        return [
            {
                "role": "system",
                "content": "You are RankGPT, an intelligent assistant that can rank passages based on their relevancy to the query.",
            },
            {
                "role": "user",
                "content": f"I will provide you with {num} passages, each indicated by number identifier []. \nRank the passages based on their relevance to query: {query}.",
            },
            {"role": "assistant", "content": "Okay, please provide the passages."},
        ]

    def _get_postfix_prompt(self, query, num):
        """
        Generates the final prompt for the LLM to request ranking output.

        Args:
            query (str): The query to rank contexts against.
            num (int): The number of passages to be ranked.

        Returns:
            Dict[str, str]: The prompt to finalize the ranking request.
        """
        example_ordering = "[2] > [1]"
        return {
            "role": "user",
            "content": f"Search Query: {query}.\nRank the {num} passages above based on their relevance to the search query. All the passages should be included and listed using identifiers, in descending order of relevance. The output format should be [] > [], e.g., {example_ordering}, Only respond with the ranking results, do not say any word or explain.",
        }



    def rank(self, documents: List[Document] ) -> List[Document]:
        """
        Reranks a list of documents using FlashRank.

        Args:
            documents (List[Document]): A list of Document instances to rerank.

        Returns:
            List[Document]: Documents with updated `reorder_contexts` after reranking.
        """
        for document in tqdm(documents, desc="Reranking Documents"):
            if len(document.contexts) == 0:
                continue
            query = document.question.question
            passages = document.contexts
            if self.llm_model is not None:
                document.reorder_contexts=self._listwisellm(query,passages)
            else:
                document.reorder_contexts=self._pairwisecrossencoding(query,passages)
        return documents
    def _listwisellm(self,query,passages):
        """
        Performs listwise reranking using an LLM model.

        Args:
            query (str): The search query.
            passages (List[Document]): The list of passages to be ranked.

        Returns:
            List[Document]: Passages sorted in descending order of relevance.

        Raises:
            ImportError: If `llama_cpp` is not installed for GGUF-based listwise reranking.
        """
        if self.llm_model is not None:
            self.logger.debug("Running listwise ranking..")
            num_of_passages = len(passages)
            messages = self._get_prefix_prompt(query, num_of_passages)

            result_map = {}
            for rank, passage in enumerate(passages):
                messages.append(
                    {
                        "role": "user",
                        "content": f"[{rank + 1}] {passage.text}",
                    }
                )
                messages.append(
                        {
                            "role": "assistant", 
                            "content": f"Received passage [{rank + 1}]."
                        }
                )

                result_map[rank + 1] = passage

            messages.append(self._get_postfix_prompt(query, num_of_passages))
            raw_ranks = self.llm_model.create_chat_completion(messages)
            results = []
            for rank in raw_ranks["choices"][0]["message"]["content"].split(" > "):
                results.append(result_map[int(rank.strip("[]"))])
            return results    

        # self.session will be instantiated for ONNX based pairwise CE models
    def _pairwisecrossencoding(self,query,passages):
        """
        Performs pairwise cross-encoding reranking using an ONNX-based model.

        Args:
            query (str): The search query.
            passages (List[Document]): The list of passages to be ranked.

        Returns:
            List[Document]: Passages sorted in descending order of relevance.
        """
        passages_copy = copy.deepcopy(passages)
        self.logger.debug("Running pairwise ranking..")
        query_passage_pairs = [[query, passage.text] for passage in passages_copy]

        input_text = self.tokenizer.encode_batch(query_passage_pairs)
        input_ids = np.array([e.ids for e in input_text])
        token_type_ids = np.array([e.type_ids for e in input_text])
        attention_mask = np.array([e.attention_mask for e in input_text])

        use_token_type_ids = token_type_ids is not None and not np.all(token_type_ids == 0)

        onnx_input = {"input_ids": input_ids.astype(np.int64), "attention_mask": attention_mask.astype(np.int64)}
        if use_token_type_ids:
            onnx_input["token_type_ids"] = token_type_ids.astype(np.int64)

        outputs = self.session.run(None, onnx_input)

        logits = outputs[0]

        if logits.shape[1] == 1:
            scores = 1 / (1 + np.exp(-logits.flatten()))
        else:
            exp_logits = np.exp(logits)
            scores = exp_logits[:, 1] / np.sum(exp_logits, axis=1)

        for score, passage in zip(scores, passages_copy):
            passage.score = score

        passages_copy.sort(key=lambda x: x.score, reverse=True)
        return passages_copy

__init__(method=None, model_name=None, api_key=None, **kwargs)

Initializes the FlashRanker model for reranking.

Parameters:

Name Type Description Default
method str

The reranking method name.

None
model_name str

The name of the reranking model to be used.

None
model_dir str

Path to a custom model directory if the user provides their own model.

required
api_key str

API key for remote access (if applicable).

None

Raises:

Type Description
ValueError

If an invalid model name is provided or model files are missing.

Source code in rankify/models/flashrank.py
def __init__(self, method: str = None, model_name: str = None, api_key: str = None, **kwargs):
    """
    Initializes the FlashRanker model for reranking.

    Args:
        method (str, optional): The reranking method name.
        model_name (str, optional): The name of the reranking model to be used.
        model_dir (str, optional): Path to a custom model directory if the user provides their own model.
        api_key (str, optional): API key for remote access (if applicable).

    Raises:
        ValueError: If an invalid model name is provided or model files are missing.
    """
    max_length: int = 512
    log_level: str = "INFO"

    logging.basicConfig(level=getattr(logging, log_level.upper(), logging.INFO))
    self.logger = logging.getLogger(__name__)
    model_dir = kwargs.get("model_dir", None)
    # Predefined FlashRank models
    available_models = HF_PRE_DEFIND_MODELS['flashrank']

    if model_name:
        if model_name not in available_models:
            raise ValueError(
                f"Invalid model name '{model_name}'. Choose from: {list(available_models.keys())} or specify a custom model directory."
            )
        model_file = HF_PRE_DEFIND_MODELS['flashrank-model-file'].get(model_name)
    elif model_dir:
        model_name = "custom_model"
        model_file =kwargs.get("model_file")  # User must provide the model file name
        if not model_file:
            raise ValueError("When using a custom model directory, you must specify 'model_dir' and 'model_file'.")

    else:
        raise ValueError("Either 'model_name' or 'model_dir' must be provided.")

    # Set paths
    self.cache_dir: Path = Path(os.environ.get('RERANKING_CACHE_DIR', './cache')) / 'models'
    self.model_dir: Path = Path(model_dir) if model_dir else self.cache_dir / model_name

    # Ensure model directory exists
    if not self.model_dir.exists():
        if model_dir:
            raise FileNotFoundError(f"Custom model directory '{self.model_dir}' not found.")
        self.logger.info(f"Downloading model '{model_name}'...")
        self._download_model_files(model_name)

    listwise_rankers = {'rank_zephyr_7b_v1_full'}
    self.llm_model = None

    if model_name in listwise_rankers:
        try:
            from llama_cpp import Llama
            self.llm_model = Llama(
                model_path=str(self.model_dir / model_file),
                n_ctx=max_length,
                n_threads=8,
            )
        except ImportError:
            raise ImportError("Please install 'pip install flashrank[listwise]' to use listwise rerankers.")

    else:
        self.session = ort.InferenceSession(str(self.model_dir / model_file))
        self.tokenizer: Tokenizer = self._get_tokenizer(max_length)

rank(documents)

Reranks a list of documents using FlashRank.

Parameters:

Name Type Description Default
documents List[Document]

A list of Document instances to rerank.

required

Returns:

Type Description
List[Document]

List[Document]: Documents with updated reorder_contexts after reranking.

Source code in rankify/models/flashrank.py
def rank(self, documents: List[Document] ) -> List[Document]:
    """
    Reranks a list of documents using FlashRank.

    Args:
        documents (List[Document]): A list of Document instances to rerank.

    Returns:
        List[Document]: Documents with updated `reorder_contexts` after reranking.
    """
    for document in tqdm(documents, desc="Reranking Documents"):
        if len(document.contexts) == 0:
            continue
        query = document.question.question
        passages = document.contexts
        if self.llm_model is not None:
            document.reorder_contexts=self._listwisellm(query,passages)
        else:
            document.reorder_contexts=self._pairwisecrossencoding(query,passages)
    return documents