lupyne 3.2__tar.gz → 3.3__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.
- {lupyne-3.2 → lupyne-3.3}/PKG-INFO +2 -2
- {lupyne-3.2 → lupyne-3.3}/README.md +1 -1
- {lupyne-3.2 → lupyne-3.3}/lupyne/engine/__init__.py +1 -1
- {lupyne-3.2 → lupyne-3.3}/lupyne/engine/analyzers.py +1 -6
- {lupyne-3.2 → lupyne-3.3}/lupyne/engine/documents.py +7 -3
- {lupyne-3.2 → lupyne-3.3}/lupyne/engine/indexers.py +6 -14
- {lupyne-3.2 → lupyne-3.3}/lupyne/engine/queries.py +3 -3
- {lupyne-3.2 → lupyne-3.3}/lupyne/engine/utils.py +1 -1
- {lupyne-3.2 → lupyne-3.3}/lupyne.egg-info/PKG-INFO +2 -2
- {lupyne-3.2 → lupyne-3.3}/pyproject.toml +1 -2
- {lupyne-3.2 → lupyne-3.3}/tests/test_engine.py +0 -7
- {lupyne-3.2 → lupyne-3.3}/LICENSE.txt +0 -0
- {lupyne-3.2 → lupyne-3.3}/lupyne/__init__.py +0 -0
- {lupyne-3.2 → lupyne-3.3}/lupyne/py.typed +0 -0
- {lupyne-3.2 → lupyne-3.3}/lupyne/services/__init__.py +0 -0
- {lupyne-3.2 → lupyne-3.3}/lupyne/services/base.py +0 -0
- {lupyne-3.2 → lupyne-3.3}/lupyne/services/graphql.py +0 -0
- {lupyne-3.2 → lupyne-3.3}/lupyne/services/rest.py +0 -0
- {lupyne-3.2 → lupyne-3.3}/lupyne/services/settings.py +0 -0
- {lupyne-3.2 → lupyne-3.3}/lupyne.egg-info/SOURCES.txt +0 -0
- {lupyne-3.2 → lupyne-3.3}/lupyne.egg-info/dependency_links.txt +0 -0
- {lupyne-3.2 → lupyne-3.3}/lupyne.egg-info/requires.txt +0 -0
- {lupyne-3.2 → lupyne-3.3}/lupyne.egg-info/top_level.txt +0 -0
- {lupyne-3.2 → lupyne-3.3}/setup.cfg +0 -0
- {lupyne-3.2 → lupyne-3.3}/tests/test_graphql.py +0 -0
- {lupyne-3.2 → lupyne-3.3}/tests/test_rest.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lupyne
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3
|
|
4
4
|
Summary: Pythonic search engine based on PyLucene.
|
|
5
5
|
Author-email: Aric Coady <aric.coady@gmail.com>
|
|
6
6
|
License: Copyright 2022 Aric Coady
|
|
@@ -92,7 +92,7 @@ PyLucene is not `pip` installable.
|
|
|
92
92
|
* [Homebrew](https://brew.sh) formula: `brew install coady/tap/pylucene`
|
|
93
93
|
|
|
94
94
|
## Dependencies
|
|
95
|
-
* PyLucene >=9.
|
|
95
|
+
* PyLucene >=9.12
|
|
96
96
|
* strawberry-graphql (if graphql option)
|
|
97
97
|
* fastapi (if rest option)
|
|
98
98
|
|
|
@@ -12,4 +12,4 @@ from .documents import Document, Field, NestedField, DateTimeField, ShapeField
|
|
|
12
12
|
from .indexers import IndexSearcher, MultiSearcher, IndexWriter, Indexer # noqa
|
|
13
13
|
|
|
14
14
|
version = tuple(map(int, lucene.VERSION.split('.')))
|
|
15
|
-
assert version >= (9,
|
|
15
|
+
assert version >= (9, 12), version
|
|
@@ -7,7 +7,6 @@ from java.util import HashMap
|
|
|
7
7
|
from org.apache.lucene import analysis, queryparser, search, util
|
|
8
8
|
from org.apache.lucene.search import uhighlight
|
|
9
9
|
from org.apache.pylucene.analysis import PythonAnalyzer, PythonTokenFilter
|
|
10
|
-
from org.apache.pylucene.queryparser.classic import PythonQueryParser
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
class TokenStream(analysis.TokenStream):
|
|
@@ -155,11 +154,7 @@ class Analyzer(PythonAnalyzer):
|
|
|
155
154
|
setattr(parser, name, value)
|
|
156
155
|
if isinstance(parser, queryparser.classic.MultiFieldQueryParser):
|
|
157
156
|
return parser.parse(parser, query)
|
|
158
|
-
|
|
159
|
-
return parser.parse(query)
|
|
160
|
-
finally:
|
|
161
|
-
if isinstance(parser, PythonQueryParser):
|
|
162
|
-
parser.finalize()
|
|
157
|
+
return parser.parse(query)
|
|
163
158
|
|
|
164
159
|
def highlight(self, query: search.Query, field: str, content: str, count: int = 1) -> str:
|
|
165
160
|
"""Return highlighted content.
|
|
@@ -348,7 +348,7 @@ class Hits:
|
|
|
348
348
|
self.searcher, self.scoredocs = searcher, scoredocs
|
|
349
349
|
if hasattr(count, 'relation'):
|
|
350
350
|
cls = int if count.relation == search.TotalHits.Relation.EQUAL_TO else float
|
|
351
|
-
count = cls(count.value)
|
|
351
|
+
count = cls(count.value() if lucene.VERSION.startswith('10.') else count.value)
|
|
352
352
|
self.count, self.fields = count, fields
|
|
353
353
|
|
|
354
354
|
def select(self, *fields: str):
|
|
@@ -450,8 +450,12 @@ class Groups:
|
|
|
450
450
|
def __getitem__(self, index):
|
|
451
451
|
hits = groupdocs = self.groupdocs[index]
|
|
452
452
|
if isinstance(groupdocs, grouping.GroupDocs):
|
|
453
|
-
|
|
454
|
-
|
|
453
|
+
if lucene.VERSION.startswith('10.'): # pragma: no cover
|
|
454
|
+
hits = Hits(self.searcher, groupdocs.scoreDocs(), groupdocs.totalHits())
|
|
455
|
+
hits.value = convert(groupdocs.groupValue())
|
|
456
|
+
else:
|
|
457
|
+
hits = Hits(self.searcher, groupdocs.scoreDocs, groupdocs.totalHits)
|
|
458
|
+
hits.value = convert(groupdocs.groupValue)
|
|
455
459
|
hits.fields = self.fields
|
|
456
460
|
return hits
|
|
457
461
|
|
|
@@ -273,7 +273,7 @@ class IndexReader:
|
|
|
273
273
|
yield doc, list(positions)
|
|
274
274
|
|
|
275
275
|
def vector(self, id, field):
|
|
276
|
-
terms = self.
|
|
276
|
+
terms = self.termVectors().get(id, field)
|
|
277
277
|
termsenum = terms.iterator() if terms else index.TermsEnum.EMPTY
|
|
278
278
|
terms = map(operator.methodcaller('utf8ToString'), util.BytesRefIterator.cast_(termsenum))
|
|
279
279
|
return termsenum, terms
|
|
@@ -373,7 +373,7 @@ class IndexSearcher(search.IndexSearcher, IndexReader):
|
|
|
373
373
|
yield (doc + offset), values
|
|
374
374
|
offset += reader.maxDoc()
|
|
375
375
|
|
|
376
|
-
def parse(self, query, spellcheck=False, **kwargs):
|
|
376
|
+
def parse(self, query, spellcheck=False, **kwargs) -> search.Query:
|
|
377
377
|
if isinstance(query, search.Query):
|
|
378
378
|
return query
|
|
379
379
|
if spellcheck:
|
|
@@ -394,8 +394,7 @@ class IndexSearcher(search.IndexSearcher, IndexReader):
|
|
|
394
394
|
"""
|
|
395
395
|
if len(query) > 1:
|
|
396
396
|
return self.docFreq(index.Term(*query))
|
|
397
|
-
|
|
398
|
-
return super().count(query)
|
|
397
|
+
return super().count(self.parse(*query, **options) if query else Query.alldocs())
|
|
399
398
|
|
|
400
399
|
def collector(self, count=None, sort=None, reverse=False, scores=False, mincount=1000):
|
|
401
400
|
if count is None:
|
|
@@ -403,12 +402,12 @@ class IndexSearcher(search.IndexSearcher, IndexReader):
|
|
|
403
402
|
count = min(count, self.maxDoc() or 1)
|
|
404
403
|
mincount = max(count, mincount)
|
|
405
404
|
if sort is None:
|
|
406
|
-
return search.
|
|
405
|
+
return search.TopScoreDocCollectorManager(count, mincount).newCollector()
|
|
407
406
|
if isinstance(sort, str):
|
|
408
407
|
sort = self.sortfield(sort, reverse=reverse)
|
|
409
408
|
if not isinstance(sort, search.Sort):
|
|
410
409
|
sort = search.Sort(sort)
|
|
411
|
-
return search.
|
|
410
|
+
return search.TopFieldCollectorManager(sort, count, mincount).newCollector()
|
|
412
411
|
|
|
413
412
|
def search(
|
|
414
413
|
self,
|
|
@@ -418,7 +417,6 @@ class IndexSearcher(search.IndexSearcher, IndexReader):
|
|
|
418
417
|
reverse=False,
|
|
419
418
|
scores=False,
|
|
420
419
|
mincount=1000,
|
|
421
|
-
timeout=None,
|
|
422
420
|
**parser,
|
|
423
421
|
) -> Hits:
|
|
424
422
|
"""Run query and return [Hits][lupyne.engine.documents.Hits].
|
|
@@ -433,17 +431,11 @@ class IndexSearcher(search.IndexSearcher, IndexReader):
|
|
|
433
431
|
reverse: reverse flag used with sort
|
|
434
432
|
scores: compute scores for candidate results when sorting
|
|
435
433
|
mincount: total hit count accuracy threshold
|
|
436
|
-
timeout: stop search after elapsed number of seconds
|
|
437
434
|
**parser: [parse][lupyne.engine.analyzers.Analyzer.parse]` options
|
|
438
435
|
"""
|
|
439
436
|
query = Query.alldocs() if query is None else self.parse(query, **parser)
|
|
440
437
|
results = cache = collector = self.collector(count, sort, reverse, scores, mincount)
|
|
441
|
-
|
|
442
|
-
if timeout is not None:
|
|
443
|
-
results = search.TimeLimitingCollector(collector, counter, int(timeout * 1000))
|
|
444
|
-
with suppress(search.TimeLimitingCollector.TimeExceededException):
|
|
445
|
-
super().search(query, results)
|
|
446
|
-
timeout = None
|
|
438
|
+
super().search(query, results)
|
|
447
439
|
if isinstance(cache, search.CachingCollector):
|
|
448
440
|
collector = search.TotalHitCountCollector()
|
|
449
441
|
cache.replay(collector)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from collections.abc import Callable, Iterable
|
|
1
|
+
from collections.abc import Callable, Iterable
|
|
2
2
|
import lucene # noqa
|
|
3
3
|
from java.lang import Double, Integer, Long
|
|
4
4
|
from java.util import Arrays
|
|
@@ -27,7 +27,7 @@ class Query:
|
|
|
27
27
|
@classmethod
|
|
28
28
|
def terms(cls, name: str, values) -> 'Query':
|
|
29
29
|
"""Return lucene TermInSetQuery, optimizing a SHOULD BooleanQuery of many terms."""
|
|
30
|
-
return cls(search.TermInSetQuery, name, list(map(util.BytesRef, values)))
|
|
30
|
+
return cls(search.TermInSetQuery, name, Arrays.asList(list(map(util.BytesRef, values))))
|
|
31
31
|
|
|
32
32
|
@classmethod
|
|
33
33
|
def boolean(cls, occur, *queries, **terms):
|
|
@@ -274,8 +274,8 @@ class DocValues:
|
|
|
274
274
|
|
|
275
275
|
class SortedSet(Sorted):
|
|
276
276
|
def __getitem__(self, id: int):
|
|
277
|
-
ords: Iterator = iter(self.docvalues.nextOrd, self.docvalues.NO_MORE_ORDS)
|
|
278
277
|
if self.docvalues.advanceExact(id):
|
|
278
|
+
ords = (self.docvalues.nextOrd() for _ in range(self.docvalues.docValueCount()))
|
|
279
279
|
return tuple(self.type(self.docvalues.lookupOrd(ord)) for ord in ords)
|
|
280
280
|
|
|
281
281
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lupyne
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3
|
|
4
4
|
Summary: Pythonic search engine based on PyLucene.
|
|
5
5
|
Author-email: Aric Coady <aric.coady@gmail.com>
|
|
6
6
|
License: Copyright 2022 Aric Coady
|
|
@@ -92,7 +92,7 @@ PyLucene is not `pip` installable.
|
|
|
92
92
|
* [Homebrew](https://brew.sh) formula: `brew install coady/tap/pylucene`
|
|
93
93
|
|
|
94
94
|
## Dependencies
|
|
95
|
-
* PyLucene >=9.
|
|
95
|
+
* PyLucene >=9.12
|
|
96
96
|
* strawberry-graphql (if graphql option)
|
|
97
97
|
* fastapi (if rest option)
|
|
98
98
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "lupyne"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.3"
|
|
4
4
|
description = "Pythonic search engine based on PyLucene."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.9"
|
|
@@ -37,7 +37,6 @@ graphql = ["strawberry-graphql[asgi]>=0.221"]
|
|
|
37
37
|
|
|
38
38
|
[tool.ruff]
|
|
39
39
|
line-length = 100
|
|
40
|
-
extend-include = ["*.ipynb"]
|
|
41
40
|
|
|
42
41
|
[tool.ruff.format]
|
|
43
42
|
quote-style = "preserve"
|
|
@@ -398,10 +398,6 @@ def test_grouping(tempdir, indexer, zipcodes):
|
|
|
398
398
|
assert all(grouping.search(indexer.indexSearcher, Q.alldocs()).facets.values())
|
|
399
399
|
assert len(grouping) == len(list(grouping)) > 100
|
|
400
400
|
assert set(grouping) > set(facets)
|
|
401
|
-
hits = indexer.search(query, timeout=-1)
|
|
402
|
-
assert not hits and not hits.count and math.isnan(hits.maxscore)
|
|
403
|
-
hits = indexer.search(query, timeout=10)
|
|
404
|
-
assert len(hits) == hits.count == indexer.count(query) and hits.maxscore == 1.0
|
|
405
401
|
directory = store.ByteBuffersDirectory()
|
|
406
402
|
query = Q.term('state', 'CA')
|
|
407
403
|
size = indexer.copy(directory, query)
|
|
@@ -465,9 +461,6 @@ def test_fields(indexer, constitution):
|
|
|
465
461
|
engine.Field('', stored='invalid')
|
|
466
462
|
with pytest.raises(AttributeError):
|
|
467
463
|
engine.Field('', invalid=None)
|
|
468
|
-
with pytest.raises(lucene.JavaError):
|
|
469
|
-
with engine.utils.suppress(search.TimeLimitingCollector.TimeExceededException):
|
|
470
|
-
document.Field('name', 'value', document.FieldType())
|
|
471
464
|
assert str(engine.Field.String('')) == str(
|
|
472
465
|
document.StringField('', '', document.Field.Store.NO).fieldType()
|
|
473
466
|
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|