Quickstart#

The fastest way to use nind from Python is the high-level API in nind.nind_engine: NindIndexer builds a binary index from a list of files, and NindEngine opens that index and answers BM25-ranked search queries.

Index a corpus#

from nind.nind_engine import NindIndexer

indexer = NindIndexer(index_dir="indices", prefix="corpus")
indexer.index_files([
    "src/py/nind/NindFile.py",
    "src/py/nind/NindPadFile.py",
    "src/py/nind/nind_engine.py",
])

This writes three files into indices/: corpus.nindlexiconindex, corpus.nindtermindex and corpus.nindlocalindex. index_dir must already exist; each input file becomes one document, identified externally by its position in the list (0, 1, 2, …).

Search it#

from nind.nind_engine import NindEngine

engine = NindEngine("indices")
for doc_id, score in engine.search("ejcrit nombre", top_k=5):
    print(f"{doc_id}: {score:.3f}")

NindEngine auto-discovers the index by scanning index_dir for a *.nindlexiconindex file, so it only needs the directory - not the prefix.

Inspecting a document or term directly#

Beyond search, NindEngine exposes the building blocks it uses internally, which are handy for debugging relevance or inspecting a specific document:

engine.get_term_id("nombre")      # -> internal lexicon identifier, or 0
engine.get_df("nombre")           # -> how many documents contain it
engine.get_tf("nombre", doc_id=1) # -> occurrences in that one document
engine.get_doc_len(doc_id=1)      # -> document length in tokens

Reading files written by the C++ implementation#

Every class NindEngine builds on (NindLexiconindex, NindTermindex, NindLocalindex) can also open index files produced by the C++ stack directly - they only need the binary files on disk, not anything written by NindIndexer. NindTermindex and NindLocalindex do need the lexicon’s identification stamp to look anything up (a cross-check the underlying format itself requires), so open the lexicon first:

from nind.NindLexiconindex import NindLexiconindex
from nind.NindTermindex import NindTermindex

lexicon = NindLexiconindex("/path/to/corpus.nindlexiconindex")
term_index = NindTermindex("/path/to/corpus.nindtermindex", lexicon.donneIdentification())
for term_cg in term_index.donneListeTermesCG(term_id):
    print(term_cg.cg, term_cg.frequency, term_cg.documents)

donneListeTermesCG (and the equivalent lookup methods on the other reader classes) return the nind._native objects directly - here, a list of TermCG, each with .cg/.frequency/.documents (a list of Document, each with .ident/.frequency) - rather than plain tuples.

See Architecture for how these lower-level classes relate to each other, and API reference for the full reference.