Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

documents: optimize serialization #2309

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions rero_ils/modules/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ def flush_and_refresh(cls):
"""Flush and refresh index."""
current_search.flush_and_refresh(cls.Meta.index)

def get_record_by_pid(self, pid, fields=None):
"""Search by pid."""
query = self.filter('term', pid=pid).extra(size=1)
if fields:
query = query.source(includes=fields)
response = query.execute()
if response.hits.total.value != 1:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if they are two or more hits? Should the message be something like " 😱 "?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A pid value is unique. Either it exists or you have an exception?

raise NotFoundError(f'Record not found pid: {pid}')
return response.hits.hits[0]._source


class IlsRecord(Record):
"""ILS Record class."""
Expand Down
84 changes: 47 additions & 37 deletions rero_ils/modules/documents/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
from ..documents.utils import title_format_text_head
from ..documents.views import create_title_alternate_graphic, \
create_title_responsibilites, create_title_variants
from ..libraries.api import Library
from ..organisations.api import Organisation
from ..libraries.api import LibrariesSearch
from ..organisations.api import OrganisationsSearch
from ..serializers import JSONSerializer, RecordSchemaJSONV1

DEFAULT_LANGUAGE = 'en'
Expand Down Expand Up @@ -89,13 +89,14 @@ def preprocess_record(self, pid, record, links_factory=None, **kwargs):

def post_process_serialize_search(self, results, pid_fetcher):
"""Post process the search results."""
# Item filters.
view_id = None
global_view_code = current_app.config.get(
'RERO_ILS_SEARCH_GLOBAL_VIEW_CODE')
viewcode = request.args.get('view', global_view_code)
if viewcode != global_view_code:
# Maybe one more if here!
view_id = Organisation.get_record_by_viewcode(viewcode).pid
view_id = OrganisationsSearch()\
.get_record_by_viewcode(viewcode, 'pid').pid
records = results.get('hits', {}).get('hits', {})
for record in records:
metadata = record.get('metadata', {})
Expand All @@ -121,34 +122,40 @@ def post_process_serialize_search(self, results, pid_fetcher):
output.append(item)
record['metadata']['items'] = output

# Add organisation name
orgs = {}
for org_term in results.get('aggregations', {}).get(
'organisation', {}).get('buckets', []):
pid = org_term.get('key')
if pid not in orgs:
orgs['pid'] = Organisation.get_record_by_pid(pid)
name = orgs['pid'].get('name')
org_term['name'] = name
lib_buckets = self._process_library_buckets(
orgs['pid'],
org_term.get('library', {}).get('buckets', [])
)
if lib_buckets:
org_term['library']['buckets'] = lib_buckets

# TODO: this should be done in the facet factory as we compute
# unused aggs values
if (viewcode is not None) and (viewcode != global_view_code):
org = Organisation.get_record_by_viewcode(viewcode)
org_buckets = results.get('aggregations', {}).get(
'organisation', {}).get('buckets', [])
for bucket in org_buckets:
if bucket.get('key') == org.pid:
lib_agg = bucket.get('library')
if lib_agg:
results['aggregations']['library'] = lib_agg
del results['aggregations']['organisation']
# Aggregations process
if viewcode == global_view_code:
# Global view
aggr_org = request.args.getlist('organisation')
for org_term in results.get('aggregations', {})\
.get('organisation', {}).get('buckets', []):
pid = org_term.get('key')
org_term['name'] = OrganisationsSearch()\
.get_record_by_pid(pid, ['name']).name
if pid not in aggr_org:
org_term.get('library', {}).pop('buckets', None)
else:
org_term['library']['buckets'] = self\
._process_library_buckets(
pid,
org_term.get('library', {}).get('buckets', [])
)
else:
# Local view
aggregations = results.get('aggregations', {})
for org_term in aggregations.get('organisation', {})\
.get('buckets', {}):
org_pid = org_term.get('key')
if org_pid != view_id:
org_term.get('library', {}).pop('buckets', None)
else:
# Add library aggregations
aggregations.setdefault('library', {})\
.setdefault('buckets', self._process_library_buckets(
org_pid,
org_term.get('library', {}).get('buckets', [])
))
# Remove organisation aggregation
aggregations.pop('organisation', None)

# Correct document type buckets
type_buckets = results[
Expand All @@ -170,13 +177,16 @@ def _process_library_buckets(cls, org, lib_buckets):
:return processed buckets
"""
processed_buckets = []
lib_pids = list(org.get_libraries_pids())
libraries = {}
records = LibrariesSearch()\
.get_libraries_by_organisation_pid(org, ['pid', 'name'])
for record in records:
libraries[record.pid] = record.name
for bucket in lib_buckets:
if bucket.get('key') in lib_pids:
bucket['name'] = Library.get_record_by_pid(
bucket.get('key')).get('name')
key = bucket.get('key')
if key in libraries:
bucket['name'] = libraries[key]
processed_buckets.append(bucket)

return processed_buckets


Expand Down
9 changes: 9 additions & 0 deletions rero_ils/modules/libraries/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ class Meta():

default_filter = None

def get_libraries_by_organisation_pid(self, org_pid, fields=None):
"""Search libraries by organisation pid."""
query = self.filter('term', organisation__pid=org_pid)
if fields:
query = query.source(includes=fields)
response = query.execute()
for hit in response.hits.hits:
yield hit._source


class Library(IlsRecord):
"""Library class."""
Expand Down
13 changes: 13 additions & 0 deletions rero_ils/modules/organisations/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

from functools import partial

from elasticsearch.exceptions import NotFoundError

from .models import OrganisationIdentifier, OrganisationMetadata
from ..api import IlsRecord, IlsRecordsIndexer, IlsRecordsSearch
from ..fetchers import id_fetcher
Expand Down Expand Up @@ -54,6 +56,17 @@ class Meta:

default_filter = None

def get_record_by_viewcode(self, viewcode, fields=None):
"""Search by viewcode."""
query = self.filter('term', code=viewcode).extra(size=1)
if fields:
query = query.source(includes=fields)
response = query.execute()
if response.hits.total.value != 1:
raise NotFoundError(
f'Organisation viewcode {viewcode}: Result not found.')
return response.hits.hits[0]._source
Garfield-fr marked this conversation as resolved.
Show resolved Hide resolved


class Organisation(IlsRecord):
"""Organisation class."""
Expand Down