Commit 2a2a0f2f authored by fabian serin's avatar fabian serin
Browse files

Adding search API for osdu objects

parent b8c8f14d
# Copyright 2021 Schlumberger
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import List
from fastapi import APIRouter, Depends
from odes_search.models import Point, CursorQueryResponse
from app.utils import Context
from .search_v3 import (
SearchQuery,
query_type,
basic_query_request,
added_query,
query_request_with_specific_attribute,
OSDU_WELLBORE_KIND,
OSDU_WELLLOG_KIND,
OSDU_WELLBOREMARKERSET_KIND,
WELLBORE_RELATIONSHIP,
REQUIRED_ROLES_READ
)
router = APIRouter()
query_type = 'fastquery'
def get_ctx() -> Context:
return Context.current()
@router.post('/fastquery/wellbores', summary="Query with cursor",
description=f"""Get all Wellbores IDs object. <p>The wellbore kind is
{OSDU_WELLBORE_KIND} returns all records IDs IDs directly based on existing schemas</p>{REQUIRED_ROLES_READ}""",
response_model=CursorQueryResponse)
async def fastquery_wellbores(body: SearchQuery = None, ctx: Context = Depends(get_ctx)):
return await basic_query_request(query_type, OSDU_WELLBORE_KIND, ctx, body.query)
@router.post('/fastquery/wellbores/{wellbore_id}/welllogs',
summary='Query with cursor, search WellLogs IDs by wellbore ID',
description=f"""Get all WellLogs IDs objects using its relationship Wellbore ID. <p>All WellLogs linked to this
specific ID will be returned</p>
<p>The LogSet kind is {OSDU_WELLLOG_KIND} returns all records IDs directly based on existing schemas</p>{REQUIRED_ROLES_READ}""",
response_model=CursorQueryResponse)
async def fastquery_welllogs_bywellbore(wellbore_id: str, body: SearchQuery = None,
ctx: Context = Depends(get_ctx)):
query = added_query(wellbore_id, WELLBORE_RELATIONSHIP, body.query)
return await basic_query_request(query_type, OSDU_WELLLOG_KIND, ctx, query)
@router.post('/fastquery/wellbore/{wellbore_attribute}/welllogs',
summary='Query with cursor, search WellLogs IDs by wellbore attribute',
description=f"""Get all WellLogs IDs objects using a specific attribute of Wellbores. <p>All WellLogs linked to Wellbores
with this specific attribute will be returned</p>
<p>The LogSet kind is {OSDU_WELLLOG_KIND} returns all records IDs directly based on existing schemas</p>{REQUIRED_ROLES_READ}""",
response_model=CursorQueryResponse)
async def fastquery_welllogs_bywellboreattribute(wellbore_attribute: str, body: SearchQuery = None,
ctx: Context = Depends(get_ctx)):
return await query_request_with_specific_attribute(query_type, wellbore_attribute, OSDU_WELLBORE_KIND,
OSDU_WELLLOG_KIND, WELLBORE_RELATIONSHIP, ctx,
body.query)
@router.post('/fastquery/wellbores/{wellbore_id}/wellboremarkersets',
summary='Query with cursor, search wellbore markersets IDs by wellbore ID',
description=f"""Get all Wellbore Markersets IDs objects using its relationship Wellbore ID. <p>All Markers linked to this
specific ID will be returned</p>
<p>The Marker kind is {OSDU_WELLBOREMARKERSET_KIND} returns all records IDs directly based on existing schemas</p>{REQUIRED_ROLES_READ}""",
response_model=CursorQueryResponse)
async def fastquery_markers_bywellbore(wellbore_id: str, body: SearchQuery = None,
ctx: Context = Depends(get_ctx)):
query = added_query(wellbore_id, WELLBORE_RELATIONSHIP, body.query)
return await basic_query_request(query_type, OSDU_WELLBOREMARKERSET_KIND, ctx, query)
......@@ -69,19 +69,19 @@ async def query_request_with_spatial_filter(query_type: str, spatial_filter: Spa
def query_spatial_filter_builder(spacial_filter_type: str, latitude1: str = None, longitude1: float = None,
latitude2: str = None, longitude2: float = None, distance: int = None,
points: List[Point] = None):
points: List[Point] = None, geo_field: str = crs_format):
if spacial_filter_type == "bydistance":
point = Point(latitude=latitude1, longitude=longitude1)
by_distance = ByDistance(distance=distance, point=point)
spatial_filter = SpatialFilter(field=crs_format, byDistance=by_distance)
spatial_filter = SpatialFilter(field=geo_field, byDistance=by_distance)
if spacial_filter_type == "byboundingbox":
point_top_left = Point(latitude=latitude1, longitude=longitude1)
point_bottom_right = Point(latitude=latitude2, longitude=longitude2)
by_bounding_box = ByBoundingBox(topLeft=point_top_left, bottomRight=point_bottom_right)
spatial_filter = SpatialFilter(field=crs_format, byBoundingBox=by_bounding_box)
spatial_filter = SpatialFilter(field=geo_field, byBoundingBox=by_bounding_box)
if spacial_filter_type == "bygeopolygon":
by_geo_polygon = ByGeoPolygon(points=points)
spatial_filter = SpatialFilter(field=crs_format, byGeoPolygon=by_geo_polygon)
spatial_filter = SpatialFilter(field=geo_field, byGeoPolygon=by_geo_polygon)
return spatial_filter
......@@ -136,7 +136,6 @@ async def basic_query_request(query_type: str, kind: str, ctx: Context, query: s
data_partition_id=ctx.partition_id,
query_request=query_request)
async def basic_query_request_with_cursor(query_type: str, kind: str, ctx: Context, query: str = None):
returned_fields = query_type_returned_fields(query_type)
if not query:
......
# Copyright 2021 Schlumberger
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import List
from fastapi import APIRouter, Depends
from odes_search.models import (
QueryRequest,
CursorQueryResponse,
)
from app.clients.search_service_client import get_search_service
from ..common_parameters import REQUIRED_ROLES_READ
from app.utils import Context
import app.routers.search.search_wrapper as search_wrapper
from .search import (
query_type,
SearchQuery,
get_ctx,
query_type_returned_fields,
basic_query_request,
basic_query_request_with_cursor)
router = APIRouter()
#osdu kind
OSDU_WELLBORE_KIND = '*:wks:master-data--Wellbore:*'
OSDU_WELLLOG_KIND = '*:wks:work-product-component--WellLog:*'
OSDU_WELLBOREMARKERSET_KIND = '*:wks:work-product-component--WellboreMarkerSet:*'
WELLBORE_RELATIONSHIP = "WellboreID"
def create_relationships_id_str(data_type: str, id: str):
return f'data.{data_type}:\"{id}\"'
def added_query(generated_query: str, user_query: str = None):
if user_query:
query = f'{generated_query} AND ({user_query})'
else:
query = generated_query
return query
def added_relationships_query(id: str, data_type: str, query: str = None):
relationships_id = create_relationships_id_str(data_type, id)
return added_query(relationships_id, query)
async def query_request_with_specific_attribute(query_type: str, attribute: str, attribute_kind: str, kind: str,
data_type: str,
ctx: Context, query: str = None):
query_request = QueryRequest(kind=attribute_kind,
query=attribute,
returnedFields=['id'])
client = await get_search_service(ctx)
query_result = await search_wrapper.SearchWrapper.query_cursorless(
search_service=client,
data_partition_id=ctx.partition_id,
query_request=query_request)
response = CursorQueryResponse.parse_obj(query_result.dict())
if not response.results:
return query_result
relationships_ids = [create_relationships_id_str(data_type, r["id"]) for r in response.results]
id_list = ' OR '.join(relationships_ids) # [a, b, c] => 'a OR b OR c'
query = added_query(id_list, query)
returned_fields = query_type_returned_fields(query_type)
query_request = QueryRequest(kind=kind,
query=query,
returnedFields=[returned_fields])
return await search_wrapper.SearchWrapper.query_cursorless(
search_service=client,
data_partition_id=ctx.partition_id,
query_request=query_request)
@router.post('/query/wellbores', summary='Query with cursor, get wellbores',
description=f"""Get all Wellbores object. <p>The wellbore kind is {OSDU_WELLBORE_KIND}
returns all records directly based on existing schemas</p>{REQUIRED_ROLES_READ}""",
response_model=CursorQueryResponse)
async def query_wellbores(body: SearchQuery = None, ctx: Context = Depends(get_ctx)):
return await basic_query_request_with_cursor(query_type, OSDU_WELLBORE_KIND, ctx, body.query)
@router.post('/query/wellbores/{wellboreId}/welllogs', summary='Query with cursor, search WellLogs by wellbore ID',
description=f"""Get all WellLogs object using its relationship Wellbore ID. <p>All WellLogs linked to this
specific ID will be returned</p>
<p>The WellLogs kind is {OSDU_WELLLOG_KIND} returns all records directly based on existing schemas</p>{REQUIRED_ROLES_READ}""",
response_model=CursorQueryResponse)
async def query_welllogs_bywellbore(wellboreId: str, body: SearchQuery = None,
ctx: Context = Depends(get_ctx)):
query = added_relationships_query(wellboreId, WELLBORE_RELATIONSHIP, body.query)
return await basic_query_request(query_type, OSDU_WELLLOG_KIND, ctx, query)
@router.post('/query/wellbore/{wellboreAttribute}/welllogs',
summary='Query with cursor, search WellLogs by wellbore attribute',
description=f"""Get all WellLogs object using a specific attribute of Wellbores. <p>All WellLogs linked to Wellbores
with this specific attribute will be returned</p>
<p>The WellLogs kind is {OSDU_WELLLOG_KIND} returns all records directly based on existing schemas</p>{REQUIRED_ROLES_READ}""",
response_model=CursorQueryResponse)
async def query_welllogs_bywellboreattribute(wellboreAttribute: str, body: SearchQuery = None,
ctx: Context = Depends(get_ctx)):
return await query_request_with_specific_attribute(query_type, wellboreAttribute, OSDU_WELLBORE_KIND, OSDU_WELLLOG_KIND,
WELLBORE_RELATIONSHIP, ctx,
body.query)
@router.post('/query/wellbores/{wellboreId}/wellboremarkersets', summary='Query with cursor, search wellbore markersets by wellbore ID',
description=f"""Get all Wellbore Markersets objects using its relationship Wellbore ID. <p>All Markers linked to this
specific ID will be returned</p>
<p>The Wellbore Markerset kind is {OSDU_WELLBOREMARKERSET_KIND} returns all records directly based on existing schemas</p>{REQUIRED_ROLES_READ}""",
response_model=CursorQueryResponse)
async def query_markers_bywellbore(wellboreId: str, body: SearchQuery = None,
ctx: Context = Depends(get_ctx)):
query = added_relationships_query(wellboreId, WELLBORE_RELATIONSHIP, body.query)
return await basic_query_request(query_type, OSDU_WELLBOREMARKERSET_KIND, ctx, query)
......@@ -45,7 +45,7 @@ from app.routers.ddms_v3 import (
from app.routers.trajectory import trajectory_ddms_v2
from app.routers.dipset import dipset_ddms_v2, dip_ddms_v2
from app.routers.logrecognition import log_recognition
from app.routers.search import search, fast_search
from app.routers.search import search, fast_search, search_v3, fast_search_v3
from app.routers.ddms_v3 import bulk_v3
from app.clients import StorageRecordServiceClient, SearchServiceClient
from app.utils import get_http_client_session, OpenApiHandler, get_wdms_temp_dir
......@@ -172,6 +172,16 @@ wdms_app.include_router(fast_search.router, prefix='/ddms', tags=['fast-search']
Depends(require_data_partition_id, use_cache=False),
Depends(require_opendes_authorized_user, use_cache=False)])
wdms_app.include_router(search_v3.router, prefix='/ddms/v3', tags=['search'], dependencies=[
Depends(require_data_partition_id, use_cache=False),
Depends(require_opendes_authorized_user, use_cache=False)
])
wdms_app.include_router(fast_search_v3.router, prefix='/ddms/v3', tags=['fast-search'], dependencies=[
Depends(require_data_partition_id, use_cache=False),
Depends(require_opendes_authorized_user, use_cache=False)
])
wdms_app.include_router(log_recognition.router, prefix='/log-recognition', tags=['log-recognition'], dependencies=[
Depends(require_data_partition_id, use_cache=False),
Depends(require_opendes_authorized_user, use_cache=False)])
......
......@@ -47,6 +47,7 @@ hiredis==2.0.0
httpcore==0.13.3
httpx==0.18.1
idna==2.10
importlib-metadata==3.10.1
iniconfig==1.1.1
isodate==0.6.0
jmespath==0.10.0
......@@ -118,3 +119,4 @@ uvicorn==0.14.0
xmltodict==0.11.0
yarl==1.6.3
zict==2.0.0
zipp==3.4.1
......@@ -15945,6 +15945,540 @@
]
}
},
"/ddms/v3/fastquery/wellbore/{wellbore_attribute}/welllogs": {
"post": {
"description": "Get all WellLogs IDs objects using a specific attribute of Wellbores. <p>All WellLogs linked to Wellbores\n with this specific attribute will be returned</p>\n <p>The LogSet kind is *:wks:work-product-component--WellLog:* returns all records IDs directly based on existing schemas</p>\n<p>Required roles: 'users.datalake.viewers' or 'users.datalake.editors' or 'users.datalake.admins'.\n\"In addition, users must be a member of data groups to access the data.</p>\n",
"operationId": "fastquery_welllogs_bywellboreattribute_ddms_v3_fastquery_wellbore__wellbore_attribute__welllogs_post",
"parameters": [
{
"in": "path",
"name": "wellbore_attribute",
"required": true,
"schema": {
"title": "Wellbore Attribute",
"type": "string"
}
},
{
"description": "identifier of the data partition to query",
"in": "header",
"name": "data-partition-id",
"required": false,
"schema": {
"description": "identifier of the data partition to query",
"minLength": 1,
"title": "data partition id",
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SearchQuery"
}
}
}
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CursorQueryResponse"
}
}
},
"description": "Successful Response"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
"description": "Validation Error"
}
},
"security": [
{
"HTTPBearer": []
}
],
"summary": "Query with cursor, search WellLogs IDs by wellbore attribute",
"tags": [
"fast-search"
]
}
},
"/ddms/v3/fastquery/wellbores": {
"post": {
"description": "Get all Wellbores IDs object. <p>The wellbore kind is\n *:wks:master-data--Wellbore:* returns all records IDs IDs directly based on existing schemas</p>\n<p>Required roles: 'users.datalake.viewers' or 'users.datalake.editors' or 'users.datalake.admins'.\n\"In addition, users must be a member of data groups to access the data.</p>\n",
"operationId": "fastquery_wellbores_ddms_v3_fastquery_wellbores_post",
"parameters": [
{
"description": "identifier of the data partition to query",
"in": "header",
"name": "data-partition-id",
"required": false,
"schema": {
"description": "identifier of the data partition to query",
"minLength": 1,
"title": "data partition id",
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SearchQuery"
}
}
}
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CursorQueryResponse"
}
}
},
"description": "Successful Response"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
"description": "Validation Error"
}
},
"security": [
{
"HTTPBearer": []
}
],
"summary": "Query with cursor",
"tags": [
"fast-search"
]
}
},
"/ddms/v3/fastquery/wellbores/{wellbore_id}/wellboremarkersets": {
"post": {
"description": "Get all Wellbore Markersets IDs objects using its relationship Wellbore ID. <p>All Markers linked to this\n specific ID will be returned</p>\n <p>The Marker kind is *:wks:work-product-component--WellboreMarkerSet:* returns all records IDs directly based on existing schemas</p>\n<p>Required roles: 'users.datalake.viewers' or 'users.datalake.editors' or 'users.datalake.admins'.\n\"In addition, users must be a member of data groups to access the data.</p>\n",
"operationId": "fastquery_markers_bywellbore_ddms_v3_fastquery_wellbores__wellbore_id__wellboremarkersets_post",
"parameters": [
{
"in": "path",
"name": "wellbore_id",
"required": true,
"schema": {
"title": "Wellbore Id",
"type": "string"
}
},
{
"description": "identifier of the data partition to query",
"in": "header",
"name": "data-partition-id",
"required": false,
"schema": {
"description": "identifier of the data partition to query",
"minLength": 1,
"title": "data partition id",
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SearchQuery"
}
}
}
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CursorQueryResponse"
}
}
},
"description": "Successful Response"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
"description": "Validation Error"
}
},
"security": [
{
"HTTPBearer": []
}
],
"summary": "Query with cursor, search wellbore markersets IDs by wellbore ID",
"tags": [
"fast-search"
]
}
},
"/ddms/v3/fastquery/wellbores/{wellbore_id}/welllogs": {
"post": {
"description": "Get all WellLogs IDs objects using its relationship Wellbore ID. <p>All WellLogs linked to this\n specific ID will be returned</p>\n <p>The LogSet kind is *:wks:work-product-component--WellLog:* returns all records IDs directly based on existing schemas</p>\n<p>Required roles: 'users.datalake.viewers' or 'users.datalake.editors' or 'users.datalake.admins'.\n\"In addition, users must be a member of data groups to access the data.</p>\n",
"operationId": "fastquery_welllogs_bywellbore_ddms_v3_fastquery_wellbores__wellbore_id__welllogs_post",
"parameters": [
{
"in": "path",
"name": "wellbore_id",
"required": true,
"schema": {
"title": "Wellbore Id",
"type": "string"
}
},
{
"description": "identifier of the data partition to query",
"in": "header",
"name": "data-partition-id",
"required": false,
"schema": {
"description": "identifier of the data partition to query",
"minLength": 1,
"title": "data partition id",
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SearchQuery"
}
}
}
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CursorQueryResponse"
}
}
},
"description": "Successful Response"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
"description": "Validation Error"
}
},
"security": [
{
"HTTPBearer": []
}
],
"summary": "Query with cursor, search WellLogs IDs by wellbore ID",
"tags": [
"fast-search"
]
}
},
"/ddms/v3/query/wellbore/{wellboreAttribute}/welllogs": {
"post": {
"description": "Get all WellLogs object using a specific attribute of Wellbores. <p>All WellLogs linked to Wellbores\n with this specific attribute will be returned</p>\n <p>The WellLogs kind is *:wks:work-product-component--WellLog:* returns all records directly based on existing schemas</p>\n<p>Required roles: 'users.datalake.viewers' or 'users.datalake.editors' or 'users.datalake.admins'.\n\"In addition, users must be a member of data groups to access the data.</p>\n",
"operationId": "query_welllogs_bywellboreattribute_ddms_v3_query_wellbore__wellboreAttribute__welllogs_post",
"parameters": [
{
"in": "path",
"name": "wellboreAttribute",
"required": true,
"schema": {
"title": "Wellboreattribute",
"type": "string"
}
},
{
"description": "identifier of the data partition to query",
"in": "header",
"name": "data-partition-id",
"required": false,
"schema": {
"description": "identifier of the data partition to query",
"minLength": 1,
"title": "data partition id",
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SearchQuery"
}
}
}
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CursorQueryResponse"
}
}
},
"description": "Successful Response"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}