Package: npids
npidsThis package provides time- and space-efficient bi-directional lookups for identifies.
Contents are mmap'd, eliminating most load times and allowing for efficient caching
through the file system.MotivationIt's often helpful to map an external string identifier to an integer index and vice versa.
Existing techniques for doing this in Python are either slow or require a lot of memory.Getting StartedInstall via pip:pipinstallnpidsBuild a lookup:fromnpidsimportLookupLookup.build(['id1','id2','id3'],'path/to/lookup.npids')Perform forward lookups (index to ID)lookup=Lookup('path/to/lookup.npids')# individual indiceslookup.fwd[0]# -> 'id1'lookup.fwd[2]# -> 'id3'# multiple indiceslookup.fwd[0,1]# -> ['id1', 'id2']# works with numpy toolookup.fwd[np.array([0,1])]# -> array(['id1', 'id2'], dtype='<U3')Perform inverse lookups (ID to index)lookup=Lookup('path/to/lookup.npids')# individual IDslookup.inv['id1']# -> 0lookup.inv['id3']# -> 2# multiple IDslookup.inv['id1','id3']# -> [0, 2]# works with numpy toolookup.inv[np.array(['id1','id3'])]# -> array([0, 2])That's about it!CodecsThe following codecs are currently supported for forward and inverted lookups. The file format is
flexible, allowing new codecs to be added in the future.Forward:fixedbytes: Every item is stored as a fixed number of bytes (with optinoal prefix). This
serves as a fallback if other forward codecs do not work.intsequence: A sequence of integes (e.g., 49, 50, 51) is identifed (with optional prefix); only
metadata about the sequence is stored.intstored: Integers are identified (with optional prefix), but they are not in a periodic sequence
(e.g., 49, 55, 21). The integer values are encoded and stored.uuid: UUIDs are identified (with optional prefix). The byte values of the UUIDs are stored.Inverse:hash: Hashes of every item are stored on disk, enablling O(1) lookups (but with extra storage).
This serves as a fallback if other inverse codecs do not work.intsequence: The values only consist of a single forwardintsequenceblock; these values can be
used to compute the indices.intstored: The values consist of onlyintstoredblocks with values in sorted order. These values
can be deconstructed and looked up in the foward codec using a binary search.BenchmarksThe following benchmarks test the speed of building, forward/inverse lookups (10k random lookups,
both "cold" and "hot"), and the size of the structure. Rows marked with * indicate that the values
include additional overheads that are not directly related to operation -- namely,
full engines include content indexing.npids: This softwareinmem: A simple Python lookup structure in memory (a list and a dict), backed by a plaintext file
that is read into memoryTerrier: Terrier engine acccessed via the pyterrier packageLucene: Apache Lucene accessed via the pyserini packageThe benchmarks show thatnpidsis a reasonable choice for performing ID lookups.
Although it is a bit slower than loading them all into memory, it avoids the
considerable upfront cost of doing so. Compared to other approaches for loading them
from disk (Lucene, Terrier), it consumes far less storage, is built faster, and
(usually) performs the lookups considerably faster.msmarco-passage(8.8M docnos:0,1,2, ...)SystemBuild TimeCold FwdHot FwdCold InvHot InvFile Sizeinmem5.95s4ms1ms6ms2ms1.3GBnpids13.88s6ms6ms4ms2ms206BLucene* 55.39s119ms53ms194ms60ms* 130.3MBTerrier* 3m53s121ms107ms1.60s218ms* 502.9MBmsmarco-document(3.2M docnos:D1555982,D301595,D1359209, ...)SystemBuild TimeCold FwdHot FwdCold InvHot InvFile Sizeinmem1.44s3ms1ms5ms2ms27.9MBnpids13.02s6ms5ms8ms8ms42.5MBLucene* 25.57s142ms61ms162ms62ms* 67.6MBTerrier* 1m26s111ms103ms866ms197ms* 195.0MBhc4/fa(486k docnos:9064520f-bc4d-4118-a30e-7d99f5adc612,e34ce085-cc13-4a1f-90e4-81a7fbfd7f0d,fa2fc4eb-4f97-4bee-bf92-a7330a80c66f, ...)SystemBuild TimeCold FwdHot FwdCold InvHot InvFile Sizeinmem0.14s2ms1ms5ms1ms18.0MBnpids2.81s21ms20ms32ms31ms11.8MBLucene* 4.26s145ms79ms163ms75ms* 49.4MBTerrier* 14.76s125ms107ms564ms187ms* 85.1MB