From 2ec7fdf4aba34f4482557b58e75a3e523261c176 Mon Sep 17 00:00:00 2001 From: Markus Scheidgen <markus.scheidgen@gmail.com> Date: Tue, 30 Jul 2019 11:21:13 +0200 Subject: [PATCH] Added authors and comments to search. --- gui/src/components/search/SearchBar.js | 20 ++++++++++++++++++-- nomad/api/repo.py | 18 +++++++++--------- nomad/datamodel/base.py | 4 ++-- nomad/search.py | 4 +++- tests/test_api.py | 17 ++++++++++------- 5 files changed, 42 insertions(+), 21 deletions(-) diff --git a/gui/src/components/search/SearchBar.js b/gui/src/components/search/SearchBar.js index c3888f28ff..b75826fb0c 100644 --- a/gui/src/components/search/SearchBar.js +++ b/gui/src/components/search/SearchBar.js @@ -127,9 +127,19 @@ class SearchBar extends React.Component { const { data: { quantities } } = this.props const suggestions = [] - Object.keys(quantities).forEach(quantity => { + // filter out pseudo quantity total + const quantityKeys = Object.keys(quantities).filter(quantity => quantity !== 'total') + + // put authors to the end + const authorIndex = quantityKeys.indexOf('authors') + if (authorIndex >= 0) { + quantityKeys[authorIndex] = quantityKeys.splice(quantityKeys.length - 1, 1, quantityKeys[authorIndex])[0] + } + + quantityKeys.forEach(quantity => { Object.keys(quantities[quantity]).forEach(quantityValue => { - if (quantityValue.toLowerCase().startsWith(value)) { + const quantityValueLower = quantityValue.toLowerCase() + if (quantityValueLower.startsWith(value) || (quantity === 'authors' && quantityValueLower.includes(value))) { suggestions.push({ key: quantity, value: quantityValue @@ -138,6 +148,12 @@ class SearchBar extends React.Component { }) }) + // Always add as comment to the end of suggestions + suggestions.push({ + key: 'comment', + value: value + }) + return suggestions } diff --git a/nomad/api/repo.py b/nomad/api/repo.py index 69f0aabbf6..e7c7d33720 100644 --- a/nomad/api/repo.py +++ b/nomad/api/repo.py @@ -17,6 +17,7 @@ The repository API of the nomad@FAIRDI APIs. Currently allows to resolve reposit meta-data. """ +from typing import List from flask_restplus import Resource, abort, fields from flask import request, g from elasticsearch_dsl import Q @@ -110,7 +111,7 @@ repo_request_parser.add_argument( repo_request_parser.add_argument( 'scroll_id', type=str, help='The id of the current scrolling window to use.') repo_request_parser.add_argument( - 'metrics', type=str, help=( + 'metrics', type=str, action='append', help=( 'Metrics to aggregate over all quantities and their values as comma separated list. ' 'Possible values are %s.' % ', '.join(search.metrics_names))) @@ -213,16 +214,11 @@ class RepoCalcsResource(Resource): page = int(request.args.get('page', 1)) per_page = int(request.args.get('per_page', 10 if not scroll else 1000)) order = int(request.args.get('order', -1)) - metrics_str = request.args.get('metrics', '') - + metrics: List[str] = request.args.getlist('metrics') from_time = rfc3339DateTime.parse(request.args.get('from_time', '2000-01-01')) until_time_str = request.args.get('until_time', None) until_time = rfc3339DateTime.parse(until_time_str) if until_time_str is not None else datetime.datetime.utcnow() time_range = (from_time, until_time) - - metrics = [ - metric for metric in metrics_str.split(',') - if metric in search.metrics_names] except Exception: abort(400, message='bad parameter types') @@ -237,6 +233,10 @@ class RepoCalcsResource(Resource): if order not in [-1, 1]: abort(400, message='invalid pagination') + for metric in metrics: + if metric not in search.metrics_names: + abort(400, message='there is not metric %s' % metric) + q = create_owner_query() # TODO this should be removed after migration @@ -263,8 +263,8 @@ class RepoCalcsResource(Resource): return results, 200 except search.ScrollIdNotFound: abort(400, 'The given scroll_id does not exist.') - except KeyError as e: - abort(400, str(e)) + # except KeyError as e: + # abort(400, str(e)) repo_quantity_values_model = api.model('RepoQuantityValues', { diff --git a/nomad/datamodel/base.py b/nomad/datamodel/base.py index 34cdce2ab3..a5d2463596 100644 --- a/nomad/datamodel/base.py +++ b/nomad/datamodel/base.py @@ -230,7 +230,7 @@ class Domain: base_quantities = dict( authors=DomainQuantity( - elastic_field='authors.name.keyword', multi=True, + elastic_field='authors.name.keyword', multi=True, aggregations=1000, description=( 'Search for the given author. Exact keyword matches in the form "Lastname, ' 'Firstname".')), @@ -322,7 +322,7 @@ class Domain: """ return { quantity.name: quantity.aggregations - for quantity in self.quantities.values() + for quantity in self.search_quantities.values() if quantity.aggregations > 0 } diff --git a/nomad/search.py b/nomad/search.py index 8ea092f25f..59ad0586da 100644 --- a/nomad/search.py +++ b/nomad/search.py @@ -507,7 +507,8 @@ def metrics_search( order=dict(_key='asc')) buckets = search.aggs.bucket(quantity_name, terms) - add_metrics(buckets) + if quantity_name not in ['authors']: + add_metrics(buckets) add_metrics(search.aggs) @@ -517,6 +518,7 @@ def metrics_search( result = { metric: bucket[metric]['value'] for metric in metrics_to_use + if hasattr(bucket, metric) } result.update(code_runs=code_runs) return result diff --git a/tests/test_api.py b/tests/test_api.py index 4f67d039cd..fe378130f9 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -783,8 +783,8 @@ class TestRepo(): @pytest.mark.parametrize('metrics', metrics_permutations) def test_search_total_metrics(self, client, example_elastic_calcs, no_warn, metrics): - rv = client.get('/repo/?metrics=%s' % ','.join(metrics)) - assert rv.status_code == 200 + rv = client.get('/repo/?%s' % urlencode(dict(metrics=metrics), doseq=True)) + assert rv.status_code == 200, str(rv.data) data = json.loads(rv.data) total_metrics = data.get('quantities', {}).get('total', {}).get('all', None) assert total_metrics is not None @@ -794,14 +794,17 @@ class TestRepo(): @pytest.mark.parametrize('metrics', metrics_permutations) def test_search_aggregation_metrics(self, client, example_elastic_calcs, no_warn, metrics): - rv = client.get('/repo/?metrics=%s' % ','.join(metrics)) + rv = client.get('/repo/?%s' % urlencode(dict(metrics=metrics), doseq=True)) assert rv.status_code == 200 data = json.loads(rv.data) - for quantities in data.get('quantities').values(): - for metrics_result in quantities.values(): + for name, quantity in data.get('quantities').items(): + for metrics_result in quantity.values(): assert 'code_runs' in metrics_result - for metric in metrics: - assert metric in metrics_result + if name != 'authors': + for metric in metrics: + assert metric in metrics_result + else: + assert len(metrics_result) == 1 # code_runs is the only metric for authors @pytest.mark.parametrize('n_results, page, per_page', [(2, 1, 5), (1, 1, 1), (0, 2, 3)]) def test_search_pagination(self, client, example_elastic_calcs, no_warn, n_results, page, per_page): -- GitLab