fuzzy-search-rs 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,191 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "crossbeam-deque"
7
+ version = "0.8.8"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a"
10
+ dependencies = [
11
+ "crossbeam-epoch",
12
+ "crossbeam-utils",
13
+ ]
14
+
15
+ [[package]]
16
+ name = "crossbeam-epoch"
17
+ version = "0.9.21"
18
+ source = "registry+https://github.com/rust-lang/crates.io-index"
19
+ checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d"
20
+ dependencies = [
21
+ "crossbeam-utils",
22
+ ]
23
+
24
+ [[package]]
25
+ name = "crossbeam-utils"
26
+ version = "0.8.23"
27
+ source = "registry+https://github.com/rust-lang/crates.io-index"
28
+ checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6"
29
+
30
+ [[package]]
31
+ name = "either"
32
+ version = "1.19.0"
33
+ source = "registry+https://github.com/rust-lang/crates.io-index"
34
+ checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be"
35
+
36
+ [[package]]
37
+ name = "fuzzy-search-rs"
38
+ version = "0.1.0"
39
+ dependencies = [
40
+ "pyo3",
41
+ "rayon",
42
+ "rustc-hash",
43
+ ]
44
+
45
+ [[package]]
46
+ name = "heck"
47
+ version = "0.5.0"
48
+ source = "registry+https://github.com/rust-lang/crates.io-index"
49
+ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
50
+
51
+ [[package]]
52
+ name = "libc"
53
+ version = "0.2.191"
54
+ source = "registry+https://github.com/rust-lang/crates.io-index"
55
+ checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a"
56
+
57
+ [[package]]
58
+ name = "once_cell"
59
+ version = "1.21.4"
60
+ source = "registry+https://github.com/rust-lang/crates.io-index"
61
+ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
62
+
63
+ [[package]]
64
+ name = "portable-atomic"
65
+ version = "1.15.0"
66
+ source = "registry+https://github.com/rust-lang/crates.io-index"
67
+ checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
68
+
69
+ [[package]]
70
+ name = "proc-macro2"
71
+ version = "1.0.107"
72
+ source = "registry+https://github.com/rust-lang/crates.io-index"
73
+ checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
74
+ dependencies = [
75
+ "unicode-ident",
76
+ ]
77
+
78
+ [[package]]
79
+ name = "pyo3"
80
+ version = "0.30.1"
81
+ source = "registry+https://github.com/rust-lang/crates.io-index"
82
+ checksum = "229ca13b8a15bb0d1487b81ab975bfcd97513416499a8312011b6036e42e0de4"
83
+ dependencies = [
84
+ "libc",
85
+ "once_cell",
86
+ "portable-atomic",
87
+ "pyo3-build-config",
88
+ "pyo3-ffi",
89
+ "pyo3-macros",
90
+ ]
91
+
92
+ [[package]]
93
+ name = "pyo3-build-config"
94
+ version = "0.30.1"
95
+ source = "registry+https://github.com/rust-lang/crates.io-index"
96
+ checksum = "70130e2b6dd1ee589a8788026a429561ca5c40fa7a2fa7914c2282eddae24700"
97
+ dependencies = [
98
+ "target-lexicon",
99
+ ]
100
+
101
+ [[package]]
102
+ name = "pyo3-ffi"
103
+ version = "0.30.1"
104
+ source = "registry+https://github.com/rust-lang/crates.io-index"
105
+ checksum = "5e7ff73c555c286d212d4ce7e5fbda845a973c4f61bd5f160f5f2c3c2a04d1c4"
106
+ dependencies = [
107
+ "libc",
108
+ "pyo3-build-config",
109
+ ]
110
+
111
+ [[package]]
112
+ name = "pyo3-macros"
113
+ version = "0.30.1"
114
+ source = "registry+https://github.com/rust-lang/crates.io-index"
115
+ checksum = "c46d2e5862c7bb8207e3b639f713dda3c499933444784154c11d013c5a691b60"
116
+ dependencies = [
117
+ "proc-macro2",
118
+ "pyo3-macros-backend",
119
+ "quote",
120
+ "syn",
121
+ ]
122
+
123
+ [[package]]
124
+ name = "pyo3-macros-backend"
125
+ version = "0.30.1"
126
+ source = "registry+https://github.com/rust-lang/crates.io-index"
127
+ checksum = "38b89f066f2ae72a2aef52d1537ca2fcd104440ebfadee06e97aa90738a25b9b"
128
+ dependencies = [
129
+ "heck",
130
+ "proc-macro2",
131
+ "quote",
132
+ "syn",
133
+ ]
134
+
135
+ [[package]]
136
+ name = "quote"
137
+ version = "1.0.47"
138
+ source = "registry+https://github.com/rust-lang/crates.io-index"
139
+ checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
140
+ dependencies = [
141
+ "proc-macro2",
142
+ ]
143
+
144
+ [[package]]
145
+ name = "rayon"
146
+ version = "1.12.0"
147
+ source = "registry+https://github.com/rust-lang/crates.io-index"
148
+ checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
149
+ dependencies = [
150
+ "either",
151
+ "rayon-core",
152
+ ]
153
+
154
+ [[package]]
155
+ name = "rayon-core"
156
+ version = "1.13.0"
157
+ source = "registry+https://github.com/rust-lang/crates.io-index"
158
+ checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
159
+ dependencies = [
160
+ "crossbeam-deque",
161
+ "crossbeam-utils",
162
+ ]
163
+
164
+ [[package]]
165
+ name = "rustc-hash"
166
+ version = "2.1.3"
167
+ source = "registry+https://github.com/rust-lang/crates.io-index"
168
+ checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
169
+
170
+ [[package]]
171
+ name = "syn"
172
+ version = "3.0.10"
173
+ source = "registry+https://github.com/rust-lang/crates.io-index"
174
+ checksum = "4ae9ccbea3a7b0b09443036490c8f34a8b1b760fd345e5c0dae0aac718faea79"
175
+ dependencies = [
176
+ "proc-macro2",
177
+ "quote",
178
+ "unicode-ident",
179
+ ]
180
+
181
+ [[package]]
182
+ name = "target-lexicon"
183
+ version = "0.13.5"
184
+ source = "registry+https://github.com/rust-lang/crates.io-index"
185
+ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
186
+
187
+ [[package]]
188
+ name = "unicode-ident"
189
+ version = "1.0.27"
190
+ source = "registry+https://github.com/rust-lang/crates.io-index"
191
+ checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
@@ -0,0 +1,20 @@
1
+ [package]
2
+ name = "fuzzy-search-rs"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ description = "Rust backend for the skipgram scan and candidate building of fuzzy-search"
6
+ license = "MIT"
7
+ readme = "README.md"
8
+
9
+ [lib]
10
+ name = "fuzzy_search_rs"
11
+ crate-type = ["cdylib", "rlib"]
12
+
13
+ [dependencies]
14
+ pyo3 = { version = "0.30", features = ["extension-module", "abi3-py310"] }
15
+ rayon = "1"
16
+ rustc-hash = "2"
17
+
18
+ [profile.release]
19
+ lto = "fat"
20
+ codegen-units = 1
@@ -0,0 +1,5 @@
1
+ Metadata-Version: 2.4
2
+ Name: fuzzy-search-rs
3
+ Version: 0.1.0
4
+ Summary: Rust backend for the skipgram scan and candidate building of fuzzy-search
5
+ Requires-Python: >=3.10
@@ -0,0 +1,102 @@
1
+ # fuzzy-search-rs
2
+
3
+ Optional Rust backend for `FuzzyPhraseSearcher` in [fuzzy-search](../README.md). It returns exactly the
4
+ same matches as the Python implementation, about 35 times faster on one thread, and runs batches on
5
+ several threads without the GIL.
6
+
7
+ ## Wheels
8
+
9
+ The extension is built as an abi3 wheel: one wheel per platform works on every CPython from 3.10 on.
10
+ The workflow `.github/workflows/rust-wheels.yml` builds and tests wheels for Linux (x86_64 and aarch64,
11
+ manylinux2014; x86_64 musllinux), macOS (universal2: Intel and Apple silicon) and Windows (x64 and
12
+ arm64), and uploads them as workflow artifacts. Publishing to PyPI is not automated.
13
+
14
+ ## Build and install
15
+
16
+ Needs a Rust toolchain and [maturin](https://www.maturin.rs/). From this directory:
17
+
18
+ ```bash
19
+ maturin build --release
20
+ ```
21
+
22
+ Other platforms from macOS (with rustup's toolchain first on `PATH`; Homebrew's `rust` has only the
23
+ host target):
24
+
25
+ ```bash
26
+ rustup target add x86_64-apple-darwin x86_64-unknown-linux-gnu
27
+ ```
28
+
29
+ ```bash
30
+ maturin build --release --target universal2-apple-darwin
31
+ ```
32
+
33
+ ```bash
34
+ pip install ziglang && maturin build --release --target x86_64-unknown-linux-gnu --zig --compatibility manylinux2014
35
+ ```
36
+
37
+ Cross-building aarch64 Linux with zig currently fails at link time (zig rejects rustc's
38
+ `--fix-cortex-a53-843419` flag), and Windows wheels need a Windows machine; CI builds both natively.
39
+
40
+ ```bash
41
+ uv pip install --python ../.venv/bin/python --reinstall target/wheels/fuzzy_search_rs-*.whl
42
+ ```
43
+
44
+ or, with pip, `pip install target/wheels/fuzzy_search_rs-*.whl`.
45
+
46
+ ## Use
47
+
48
+ Select the backend in the searcher config:
49
+
50
+ ```python
51
+ from fuzzy_search import FuzzyPhraseSearcher
52
+
53
+ searcher = FuzzyPhraseSearcher(phrase_model=phrases, config={'backend': 'auto'})
54
+ matches = searcher.find_matches(text) # one text
55
+ results = searcher.find_matches_batch(texts, workers=0) # many texts, one thread per CPU
56
+ ```
57
+
58
+ - `'auto'` (default): Rust when installed and possible, otherwise Python.
59
+ - `'python'`: the Python implementation.
60
+ - `'rust'`: the Rust backend; raises `RuntimeError` if it is not installed or cannot reproduce the
61
+ searcher's settings.
62
+
63
+ With the Rust backend, `find_matches_batch(texts, workers=n)` uses `n` threads (0: one per CPU) instead
64
+ of worker processes, so no `if __name__ == '__main__':` guard is needed.
65
+
66
+ ## What runs in Rust
67
+
68
+ `find_matches` runs exact matching in Python, then Rust does, per text:
69
+
70
+ 1. the skipgram scan (`Searcher.find_skipgram_matches`),
71
+ 2. candidate building (`get_skipmatch_candidates`, `CandidatePartial`),
72
+ 3. word-boundary adjustment (`adjust_match_offsets`) and per-phrase overlap filtering
73
+ (`filter_overlapping_phrase_candidates`),
74
+ 4. scoring (`PhraseMatch.add_scores`: character overlap, ngram overlap, `Levenshtein.ratio`).
75
+
76
+ Python then builds `PhraseMatch` objects only for candidates that pass the thresholds, and runs the
77
+ remaining steps (distractors, combining with exact matches, offset thresholds, overlap filtering).
78
+
79
+ The Rust code mirrors the Python code step by step, including quirks such as group ordering, the
80
+ `next_start_offset and ...` truthiness test and `Counter` entries that drop to zero. Offsets are Unicode
81
+ code points, as in Python slicing.
82
+
83
+ ## Limits and differences
84
+
85
+ - `ngram_size` up to 6 (skipgrams are packed into 128-bit keys). Larger sizes fall back to Python
86
+ (`'auto'`) or raise (`'rust'`).
87
+ - Phrases with `max_end_offset` fall back to Python, which raises an `AttributeError` for them.
88
+ - `debug > 0` always runs the Python code, so its debug output is unchanged.
89
+ - With `ignorecase`, texts whose lowercase has a different length (such as `İ`) or that contain a capital
90
+ sigma `Σ` are scored in Python, because there slicing the lowercased text differs from lowercasing a slice.
91
+ - Where Python would raise `ZeroDivisionError` or `IndexError` on degenerate input (a phrase shorter
92
+ than `ngram_size`), the Rust backend raises `ValueError`.
93
+
94
+ ## Verification
95
+
96
+ - `test/test_search_rust_backend.py` compares both backends over a grid of settings and texts, including
97
+ threaded batches, and checks backend selection and pickling.
98
+ - The regression fixture runs with either backend:
99
+
100
+ ```bash
101
+ .venv/bin/python -m pytest test/regression --regression-backend rust --regression-exact --regression-full
102
+ ```
@@ -0,0 +1,12 @@
1
+ [build-system]
2
+ requires = ["maturin>=1.5,<2"]
3
+ build-backend = "maturin"
4
+
5
+ [project]
6
+ name = "fuzzy-search-rs"
7
+ version = "0.1.0"
8
+ description = "Rust backend for the skipgram scan and candidate building of fuzzy-search"
9
+ requires-python = ">=3.10"
10
+
11
+ [tool.maturin]
12
+ features = ["pyo3/extension-module"]