oarepo-runtime 1.7.1__py3-none-any.whl → 1.8.0__py3-none-any.whl
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.
- oarepo_runtime/records/systemfields/__init__.py +16 -2
- oarepo_runtime/records/systemfields/icu.py +93 -17
- oarepo_runtime/services/custom_fields/mappings.py +9 -30
- oarepo_runtime/utils/index.py +11 -0
- {oarepo_runtime-1.7.1.dist-info → oarepo_runtime-1.8.0.dist-info}/METADATA +1 -1
- {oarepo_runtime-1.7.1.dist-info → oarepo_runtime-1.8.0.dist-info}/RECORD +10 -9
- {oarepo_runtime-1.7.1.dist-info → oarepo_runtime-1.8.0.dist-info}/WHEEL +0 -0
- {oarepo_runtime-1.7.1.dist-info → oarepo_runtime-1.8.0.dist-info}/entry_points.txt +0 -0
- {oarepo_runtime-1.7.1.dist-info → oarepo_runtime-1.8.0.dist-info}/licenses/LICENSE +0 -0
- {oarepo_runtime-1.7.1.dist-info → oarepo_runtime-1.8.0.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,26 @@
|
|
1
|
-
from .icu import
|
1
|
+
from .icu import (
|
2
|
+
FulltextIndexField,
|
3
|
+
ICUField,
|
4
|
+
ICUSearchField,
|
5
|
+
ICUSortField,
|
6
|
+
ICUSuggestField,
|
7
|
+
)
|
2
8
|
from .mapping import MappingSystemFieldMixin, SystemFieldDumperExt
|
3
|
-
from .selectors import
|
9
|
+
from .selectors import (
|
10
|
+
FilteredSelector,
|
11
|
+
FirstItemSelector,
|
12
|
+
MultiSelector,
|
13
|
+
PathSelector,
|
14
|
+
Selector,
|
15
|
+
)
|
4
16
|
from .synthetic import SyntheticSystemField
|
5
17
|
|
6
18
|
__all__ = (
|
7
19
|
"ICUField",
|
8
20
|
"ICUSuggestField",
|
9
21
|
"ICUSortField",
|
22
|
+
"ICUSearchField",
|
23
|
+
"FulltextIndexField",
|
10
24
|
"MappingSystemFieldMixin",
|
11
25
|
"SystemFieldDumperExt",
|
12
26
|
"SyntheticSystemField",
|
@@ -37,11 +37,18 @@ class ICUField(MappingSystemFieldMixin, SystemField):
|
|
37
37
|
ret = []
|
38
38
|
for l in lookup_key(data, f"{self.source_field}"):
|
39
39
|
if isinstance(l.value, str):
|
40
|
+
# take single value as being always the the language provided
|
40
41
|
ret.append(l.value)
|
41
42
|
elif isinstance(l.value, dict):
|
43
|
+
# expected to be {"cs": "", "en": ""}
|
42
44
|
val = l.value.get(language)
|
43
45
|
if val:
|
44
46
|
ret.append(val)
|
47
|
+
elif "lang" in l.value:
|
48
|
+
# for [{"lang": "", "value": ""}, ...] we get each item separately
|
49
|
+
# that's why we do not iterate over l.value
|
50
|
+
if l.value["lang"] == language:
|
51
|
+
ret.append(l.value["value"])
|
45
52
|
return ret
|
46
53
|
|
47
54
|
def search_dump(self, data, record):
|
@@ -132,23 +139,24 @@ class ICUSuggestField(ICUField):
|
|
132
139
|
}
|
133
140
|
|
134
141
|
|
135
|
-
class
|
136
|
-
"""
|
137
|
-
A field that adds stemming-aware search field
|
138
|
-
"""
|
142
|
+
class ICUSearchAnalyzerMixin:
|
139
143
|
|
140
144
|
default_stemming_analyzers = {
|
141
145
|
"stemming_analyzer_cs": {
|
142
146
|
"tokenizer": "standard",
|
143
|
-
"filter": ["stemming_filter_cs"],
|
147
|
+
"filter": ["stemming_filter_cs", "lowercase"],
|
144
148
|
},
|
145
149
|
"stemming_analyzer_en": {
|
146
150
|
"tokenizer": "standard",
|
147
|
-
"filter": ["stemming_filter_en"],
|
151
|
+
"filter": ["stemming_filter_en", "lowercase"],
|
148
152
|
},
|
149
153
|
"ascii_folding_analyzer": {
|
150
154
|
"tokenizer": "standard",
|
151
|
-
"filter": ["ascii_folding_filter"],
|
155
|
+
"filter": ["ascii_folding_filter", "lowercase"],
|
156
|
+
},
|
157
|
+
"lowercase_analyzer": {
|
158
|
+
"tokenizer": "standard",
|
159
|
+
"filter": ["lowercase"],
|
152
160
|
},
|
153
161
|
}
|
154
162
|
|
@@ -166,6 +174,25 @@ class ICUSearchField(ICUField):
|
|
166
174
|
"ascii_folding_filter": {"type": "asciifolding", "preserve_original": True},
|
167
175
|
}
|
168
176
|
|
177
|
+
@property
|
178
|
+
def mapping_settings(self):
|
179
|
+
return {
|
180
|
+
"analysis": {
|
181
|
+
"analyzer": current_app.config.get(
|
182
|
+
"OAREPO_ICU_SEARCH_ANALYZERS", self.default_stemming_analyzers
|
183
|
+
),
|
184
|
+
"filter": current_app.config.get(
|
185
|
+
"OAREPO_ICU_SEARCH_FILTERS", self.default_stemming_filters
|
186
|
+
),
|
187
|
+
}
|
188
|
+
}
|
189
|
+
|
190
|
+
|
191
|
+
class ICUSearchField(ICUSearchAnalyzerMixin, ICUField):
|
192
|
+
"""
|
193
|
+
A field that adds stemming-aware search field
|
194
|
+
"""
|
195
|
+
|
169
196
|
def __init__(self, source_field, key=None):
|
170
197
|
super().__init__(source_field=source_field, key=key)
|
171
198
|
|
@@ -187,6 +214,11 @@ class ICUSearchField(ICUField):
|
|
187
214
|
"analyzer": f"stemming_analyzer_{lang}",
|
188
215
|
"boost": 0.5,
|
189
216
|
},
|
217
|
+
"lowercase": {
|
218
|
+
"type": "text",
|
219
|
+
"boost": 0.8,
|
220
|
+
"analyzer": "lowercase_analyzer",
|
221
|
+
},
|
190
222
|
"ascii_folded": {
|
191
223
|
"type": "text",
|
192
224
|
"analyzer": "ascii_folding_analyzer",
|
@@ -200,15 +232,59 @@ class ICUSearchField(ICUField):
|
|
200
232
|
},
|
201
233
|
}
|
202
234
|
|
235
|
+
def get_values(self, data, language):
|
236
|
+
return super().get_values(data, language=language)
|
237
|
+
|
238
|
+
|
239
|
+
class FulltextIndexField(ICUSearchAnalyzerMixin, ICUField):
|
240
|
+
"""
|
241
|
+
A system field that makes the field searchable in OpenSearch,
|
242
|
+
regardless if it is indexed/analyzed, embedded in Nested or not.
|
243
|
+
|
244
|
+
It creates a top-level mapping field and copies
|
245
|
+
content of {source_field} into it. It also provides the correct mapping
|
246
|
+
for the field based on the current configuration of the application.
|
247
|
+
|
248
|
+
Unlike the ICU, this field is a single-language and the language should
|
249
|
+
be provided when initializing the field.
|
250
|
+
It defaults to the BABEL_DEFAULT_LOCALE if not provided.
|
251
|
+
"""
|
252
|
+
|
253
|
+
def __init__(self, *, source_field, key=None, language=None):
|
254
|
+
super().__init__(source_field=source_field, key=key)
|
255
|
+
self.language = language
|
256
|
+
|
203
257
|
@property
|
204
|
-
def
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
258
|
+
def mapping(self):
|
259
|
+
language = self.language or current_app.config.get("BABEL_DEFAULT_LOCALE", "en")
|
260
|
+
mapping_settings = self.languages.get(language, None)
|
261
|
+
if mapping_settings:
|
262
|
+
mapping_settings = mapping_settings.get("search")
|
263
|
+
if not mapping_settings:
|
264
|
+
mapping_settings = {
|
265
|
+
"type": "text",
|
266
|
+
"boost": 1,
|
267
|
+
"fields": {
|
268
|
+
"stemmed": {
|
269
|
+
"type": "text",
|
270
|
+
"analyzer": f"stemming_analyzer_{language}",
|
271
|
+
"boost": 0.5,
|
272
|
+
},
|
273
|
+
"ascii_folded": {
|
274
|
+
"type": "text",
|
275
|
+
"analyzer": "ascii_folding_analyzer",
|
276
|
+
"boost": 0.3,
|
277
|
+
},
|
278
|
+
},
|
213
279
|
}
|
214
|
-
|
280
|
+
|
281
|
+
return {self.attr_name: mapping_settings}
|
282
|
+
|
283
|
+
def search_dump(self, data, record):
|
284
|
+
"""Dump custom field."""
|
285
|
+
data[self.attr_name] = self.get_values(data, language=self.language)
|
286
|
+
|
287
|
+
@classmethod
|
288
|
+
def search_load(cls, data, record_cls):
|
289
|
+
"""Load custom field."""
|
290
|
+
data.pop(cls.attr_name, None)
|
@@ -9,17 +9,16 @@ from invenio_records_resources.services.custom_fields.mappings import (
|
|
9
9
|
)
|
10
10
|
from invenio_records_resources.services.records.config import RecordServiceConfig
|
11
11
|
from invenio_records_resources.services.records.service import RecordService
|
12
|
-
from invenio_search import
|
13
|
-
from invenio_search.engine import dsl, search
|
14
|
-
from invenio_search.utils import build_alias_name
|
15
|
-
|
12
|
+
from invenio_search.engine import search
|
16
13
|
from deepmerge import always_merger
|
17
14
|
from oarepo_runtime.records.systemfields.mapping import MappingSystemFieldMixin
|
18
15
|
import json
|
19
|
-
import os
|
20
16
|
|
21
17
|
from pathlib import Path
|
22
18
|
|
19
|
+
from oarepo_runtime.utils.index import prefixed_index
|
20
|
+
|
21
|
+
|
23
22
|
class Mapping(InvenioMapping):
|
24
23
|
@classmethod
|
25
24
|
def properties_for_fields(
|
@@ -95,21 +94,11 @@ def prepare_cf_index(record_class, config, path=[]):
|
|
95
94
|
|
96
95
|
# upload mapping
|
97
96
|
try:
|
98
|
-
record_index =
|
99
|
-
build_alias_name(
|
100
|
-
config.record_cls.index._name,
|
101
|
-
),
|
102
|
-
using=current_search_client,
|
103
|
-
)
|
97
|
+
record_index = prefixed_index(config.record_cls.index)
|
104
98
|
update_index(record_index, settings, mapping)
|
105
99
|
|
106
100
|
if hasattr(config, "draft_cls"):
|
107
|
-
draft_index =
|
108
|
-
build_alias_name(
|
109
|
-
config.draft_cls.index._name,
|
110
|
-
),
|
111
|
-
using=current_search_client,
|
112
|
-
)
|
101
|
+
draft_index = prefixed_index(config.draft_cls.index)
|
113
102
|
update_index(draft_index, settings, mapping, dynamic_templates)
|
114
103
|
|
115
104
|
except search.RequestError as e:
|
@@ -166,22 +155,12 @@ def prepare_parent_mapping(parent_class, config):
|
|
166
155
|
})
|
167
156
|
# upload mapping
|
168
157
|
try:
|
169
|
-
record_index =
|
170
|
-
build_alias_name(
|
171
|
-
config.record_cls.index._name,
|
172
|
-
),
|
173
|
-
using=current_search_client,
|
174
|
-
)
|
158
|
+
record_index = prefixed_index(config.record_cls.index)
|
175
159
|
update_index(record_index, {}, parent_mapping_merged)
|
176
160
|
|
177
161
|
if hasattr(config, "draft_cls"):
|
178
|
-
draft_index =
|
179
|
-
|
180
|
-
config.draft_cls.index._name,
|
181
|
-
),
|
182
|
-
using=current_search_client,
|
183
|
-
)
|
184
|
-
update_index(record_index, {}, parent_mapping_merged)
|
162
|
+
draft_index = prefixed_index(config.draft_cls.index) # draft index isn't used; this was a bug a suppose
|
163
|
+
update_index(draft_index, {}, parent_mapping_merged)
|
185
164
|
|
186
165
|
except search.RequestError as e:
|
187
166
|
click.secho("An error occurred while creating parent mapping.", fg="red")
|
@@ -0,0 +1,11 @@
|
|
1
|
+
from invenio_search import current_search_client
|
2
|
+
from invenio_search.utils import build_alias_name
|
3
|
+
from invenio_search.engine import dsl
|
4
|
+
|
5
|
+
def prefixed_index(index):
|
6
|
+
return dsl.Index(
|
7
|
+
build_alias_name(
|
8
|
+
index._name,
|
9
|
+
),
|
10
|
+
using = current_search_client
|
11
|
+
)
|
@@ -70,10 +70,10 @@ oarepo_runtime/records/relations/base.py,sha256=ESTwj0-eT8HRTJ8QcE5fmqzjOjBFHpQq
|
|
70
70
|
oarepo_runtime/records/relations/internal.py,sha256=OTp8iJqyl80sWDk0Q0AK42l6UsxZDABspVU_GwWza9o,1556
|
71
71
|
oarepo_runtime/records/relations/lookup.py,sha256=wi3jPfOedazOmhOMrgu50PUETc1jfSdpmjK0wvOFsEM,848
|
72
72
|
oarepo_runtime/records/relations/pid_relation.py,sha256=eojw5uIo5zXmJGge_bj6Wj2njCRY5S4o4B_h_HFyaDY,3901
|
73
|
-
oarepo_runtime/records/systemfields/__init__.py,sha256=
|
73
|
+
oarepo_runtime/records/systemfields/__init__.py,sha256=fdOvVL7L-Q4pcNHPcixYw52ydwEd9mBJVVvZT2-6ON4,667
|
74
74
|
oarepo_runtime/records/systemfields/featured_file.py,sha256=MbSaYR130_o5S9gEOblnChq-PVK4xGPGpSCrzwG3cwc,1720
|
75
75
|
oarepo_runtime/records/systemfields/has_draftcheck.py,sha256=4JkMEefPLpqtPtlTgK3UT0KzTRgyw5_Qtkss2qcz5xk,1643
|
76
|
-
oarepo_runtime/records/systemfields/icu.py,sha256=
|
76
|
+
oarepo_runtime/records/systemfields/icu.py,sha256=id4yv80DG-8XWMaSeegpoF7JWciXTHq69U2Xqo_4lW8,9700
|
77
77
|
oarepo_runtime/records/systemfields/mapping.py,sha256=tXOK_jkdY1pOUO7_VfChfDNB8UTi21GUXaidpugTnO8,1017
|
78
78
|
oarepo_runtime/records/systemfields/owner.py,sha256=dYRVBinniW7ECHuSnTAjeN6x1KhhJtNR9vxmD1KswMs,3805
|
79
79
|
oarepo_runtime/records/systemfields/record_status.py,sha256=U3kem4-JkNsT17e0iAl3HIAZ2MvO5lY_0U757aZvTKE,935
|
@@ -98,7 +98,7 @@ oarepo_runtime/services/config/link_conditions.py,sha256=5hDEtCaQt1tzjb9gGdeimsm
|
|
98
98
|
oarepo_runtime/services/config/permissions_presets.py,sha256=b1wm3JjL8KgkaH7VMkNfdMk5fXtf3X87rB7gkvaNxns,7369
|
99
99
|
oarepo_runtime/services/config/service.py,sha256=KS1eKXjRzusD_UAKanzKezua2lmo9vObwqd63dky1ik,4593
|
100
100
|
oarepo_runtime/services/custom_fields/__init__.py,sha256=_gqMcA_I3rdEZcBtCuDjO4wdVCqFML5NzaccuPx5a3o,2565
|
101
|
-
oarepo_runtime/services/custom_fields/mappings.py,sha256=
|
101
|
+
oarepo_runtime/services/custom_fields/mappings.py,sha256=U43noOuANohgoZt7YoAT3B6NgDCLKIRVKigPHzsreQU,6970
|
102
102
|
oarepo_runtime/services/entity/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
103
103
|
oarepo_runtime/services/entity/config.py,sha256=1jfdPrxSbMuKj7eOUNKRWTCPbBPyRV6MrWE4Vgf9rX0,399
|
104
104
|
oarepo_runtime/services/entity/schema.py,sha256=8TBpUFRITaBO7qCMz36cly1Hj4I1nLa9PeSAfWSa2YM,157
|
@@ -148,14 +148,15 @@ oarepo_runtime/translations/en/LC_MESSAGES/messages.mo,sha256=tq5pTCpH7cuzdwrQlp
|
|
148
148
|
oarepo_runtime/translations/en/LC_MESSAGES/messages.po,sha256=7-5S3iINOSFSI5gVdRvT5S2rbGScrheJiUJQH_fqXmY,1914
|
149
149
|
oarepo_runtime/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
150
150
|
oarepo_runtime/utils/functools.py,sha256=gKS9YZtlIYcDvdNA9cmYO00yjiXBYV1jg8VpcRUyQyg,1324
|
151
|
+
oarepo_runtime/utils/index.py,sha256=ArrUUXB-KowUcUksRKqcFpmqct4bn9alO1zd_kX2tmU,292
|
151
152
|
oarepo_runtime/utils/path.py,sha256=V1NVyk3m12_YLbj7QHYvUpE1wScO78bYsX1LOLeXDkI,3108
|
152
|
-
oarepo_runtime-1.
|
153
|
+
oarepo_runtime-1.8.0.dist-info/licenses/LICENSE,sha256=h2uWz0OaB3EN-J1ImdGJZzc7yvfQjvHVYdUhQ-H7ypY,1064
|
153
154
|
tests/marshmallow_to_json/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
154
155
|
tests/marshmallow_to_json/test_datacite_ui_schema.py,sha256=82iLj8nW45lZOUewpWbLX3mpSkpa9lxo-vK-Qtv_1bU,48552
|
155
156
|
tests/marshmallow_to_json/test_simple_schema.py,sha256=izZN9p0v6kovtSZ6AdxBYmK_c6ZOti2_z_wPT_zXIr0,1500
|
156
157
|
tests/pkg_data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
157
|
-
oarepo_runtime-1.
|
158
|
-
oarepo_runtime-1.
|
159
|
-
oarepo_runtime-1.
|
160
|
-
oarepo_runtime-1.
|
161
|
-
oarepo_runtime-1.
|
158
|
+
oarepo_runtime-1.8.0.dist-info/METADATA,sha256=2RIMYE7SkyjV-UjfAVIT-CBXIOk8ImbsxDrIweni-Mw,4788
|
159
|
+
oarepo_runtime-1.8.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
160
|
+
oarepo_runtime-1.8.0.dist-info/entry_points.txt,sha256=k7O5LZUOGsVeSpB7ulU0txBUNp1CVQG7Q7TJIVTPbzU,491
|
161
|
+
oarepo_runtime-1.8.0.dist-info/top_level.txt,sha256=bHhlkT1_RQC4IkfTQCqA3iN4KCB6cSFQlsXpQMSP-bE,21
|
162
|
+
oarepo_runtime-1.8.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|