Commit b4014438 authored by Markus Scheidgen's avatar Markus Scheidgen
Browse files

Added es search query to materials search results as reference. Added documentation for essearch.

parent c74a4b73
......@@ -258,22 +258,23 @@ def get_materials(page, per_page):
match_query = dict(match=match_query)
else:
match_query = dict(match_all={})
es_query = {
'bool': {
'must': [match_query],
'filter': filter_queries
}
}
es_request_body = {
'size': per_page,
'from': (page - 1) * per_page,
'query': {
'bool': {
'must': [match_query],
'filter': filter_queries
}
}
'query': es_query
}
es_search_results = es.search(index=es_config['index'], doc_type='material', body=es_request_body)
total_es_search_results = es_search_results['hits']['total']
materials_found_list = [render_es_result(hit['_source']) for hit in es_search_results['hits']['hits']]
return materials_found_list, total_es_search_results
return materials_found_list, total_es_search_results, { 'es_query': es_query }
@api.route('/esmaterials', methods=['POST'])
......
......@@ -40,6 +40,7 @@ def paginate(analyze_request):
if per_page is not None:
per_page = int(per_page)
additional_keys = {}
if paginate:
if page is None or page < 1:
page = 1
......@@ -49,7 +50,14 @@ def paginate(analyze_request):
kwargs["page"] = page
kwargs["per_page"] = per_page
results, total_results = func(*args, **kwargs)
func_results = func(*args, **kwargs)
assert len(func_results) == 2 or len(func_results) == 3
results, total_results = [], 0
if len(func_results) == 2:
results, total_results = func_results
elif len(func_results) == 3:
results, total_results, additional_keys = func_results
total_pages = math.ceil(total_results / per_page)
pages = {
......@@ -78,13 +86,18 @@ def paginate(analyze_request):
pages['first_url'] = url(1)
pages['last_url'] = url(total_pages)
return dict(results=results, pages=pages, total_results=total_results)
result_dict = dict(results=results, pages=pages, total_results=total_results)
else:
kwargs["page"] = 1
kwargs["per_page"] = 10000
results, total_results = func(*args, **kwargs)
return dict(results=results, total_results=total_results)
result_dict = dict(results=results, total_results=total_results)
for key, value in additional_keys.items():
result_dict[key] = value
return result_dict
return wrapped
return decorator
......@@ -434,7 +434,7 @@ This is an endpoint needed for "suggestions" feature implementation in GUI, for
# Group Material
## Search for materials using a formula, by elements or by properties [/materials]
## Search with formula, y elements or by properties [/materials]
### POST
Retrieves a list of materials (along with some specific properties) which match the formula, elements or the specified properties mentioned as filtering options in the json file sent as a **POST** request
......@@ -596,6 +596,225 @@ which will return basically all materials, paginated, having 25 items per page.
"status": 404
}
## Search with Elastic Search [/esmaterials]
### POST
Retrieves a list of materials (along with some specific properties) which match the given Elastic Search query sent as a **POST** request
The POST body needs to be a valid Elastic Search 6.x search query in JSON format. Pagination is controlled via querystring parameters `page`, `per_page`, `pagination`.
Example of a complete **POST** body:
```
{
"bool": {
"filter": [
{
"terms": {
"system_type": [
"bulk",
"2D"
]
}
},
{
"terms": {
"crystal_system": [
"monoclinic",
"tetragonal"
]
}
},
{
"script": {
"script": {
"lang": "painless",
"source": "!(doc['band_gap'][0] > 4.600000 || doc['band_gap'][1] < 2.800000)"
}
}
}
],
"must": [
{
"match": {
"atom_labels": {
"operator": "and",
"query": "Na Cl"
}
}
}
]
}
}
```
This query is equivalent to a POST to `/materials` with
```
{
"search_by": {
"exclusive": "0",
"element": "Na,Cl"
},
"system_type": ["bulk", "2D"],
"crystal_system": ["monoclinic", "tetragonal"],
"band_gap": {
"min": 2.8,
"max": 4.6
}
}
```
In fact, the `/materials` endpoints returns the internally used Elastic Search query as part of its response under
the key `es_query`. This can be a great resource of examples to get started with the Elastic Search endpoint of this API.
Using the Elastic Search index requires some insights into the index itself and the stored data to use it effectively.
The Elastic Search index contains the following mappings and respectively only these keys can be used in your queries:
```
{
"mappings":{
"material":{
"properties":{
"atom_labels":{
"type":"text",
"analyzer":"formula_analyzer"
},
"atom_labels_keyword":{
"type":"keyword"
},
"basis_set_type":{
"type":"keyword"
},
"calculations":{
"type":"long"
},
"code_name":{
"type":"keyword"
},
"crystal_system":{
"type":"keyword"
},
"formula":{
"type":"keyword"
},
"formula_reduced":{
"type":"keyword"
},
"functional_type":{
"type":"keyword"
},
"mass_density":{
"type":"float"
},
"material_hash":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"material_id":{
"type":"long"
},
"material_name":{
"type":"keyword"
},
"space_group_number":{
"type":"keyword"
},
"structure_type":{
"type":"keyword"
},
"system_type":{
"type":"keyword"
}
}
}
}
}
```
Refer to the Elastic Search [documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html) for details on mappings. The `atom_labels` text analyzer tokenizes the
atom label String into individual atoms.
Here is an example of a material in the index.
```
{
"_index":"nomad",
"_type":"material",
"_id":"1",
"_version":1,
"found":true,
"_source":{
"atom_labels":"CrW",
"mass_density":[
11979.638110468504,
11979.638110468504
],
"formula":"Cr2W",
"material_name":"Chromium Tungsten",
"system_type":"bulk",
"atom_labels_keyword":"CrW",
"calculations":1,
"formula_reduced":"Cr2W",
"space_group_number":"164",
"material_id":1,
"code_name":[
"VASP"
],
"functional_type":[
"GGA"
],
"crystal_system":"trigonal",
"material_hash":"7af577d51662f67b5da9eb295f00e002113f84ef49bcbdefc038332fe22e1a603e1cdb185c5c528692212deaace709e08fe6b3da96a1382abe9eb3d85bac81ac",
"basis_set_type":[
"Plane waves"
]
}
}
```
As a reference for the Elastic Search query language refer to the Elastic Search [documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html).
Responses of `esmaterials` are in the same format as results of `/materials`.
+ Parameters
+ body: (application/json, mandatory) - An Elastic Search 6.x search query
+ page: 2 (number, optional) - The page number to be shown
+ Default: `1`
+ per_page: 15 (number, optional) - The maximum number of items shown on page
+ Default: `25`
+ pagination: off (string, optional) - To disable the pagination, will return all results in one page.
+ Default: 'on'
+ Response 200 (application/json)
+ Body
{
"pages": {
"page": 1,
"pages": 1,
"per_page": 5,
"total": 1
},
"results": [
{
"formula": "Cr30",
"formula_reduced": "Cr",
"id": 12,
"material_name": "Chromium",
"nr_of_calculations": 1,
"space_group_number": "136",
"structure_type": null,
"system_type": "bulk"
}
],
"total_results": 1
}
## Retrieves properties of a specific material [/materials/{material_id}]
### GET
Retrieves properties of a specific material
......
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment