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

Improved Ontology Search #11

Open
juliangruendner opened this issue Jan 22, 2024 · 8 comments
Open

Improved Ontology Search #11

juliangruendner opened this issue Jan 22, 2024 · 8 comments
Assignees
Labels
enhancement New feature or request

Comments

@juliangruendner
Copy link
Contributor

juliangruendner commented Jan 22, 2024

Overview

Searching through the ontology shall become more convenient. This requires changes to the frontend and the backend as well. The frontend part (except the API to it) is not the scope of this issue, however, the input of the frontend team is much appreciated (as well as from others).

For the backend, the plan is to add an instance of elastic search that will be populated with data generated by the fhir ontology generator and queried by the backend application.

This issue is meant to collect and discuss ideas first.

Current State

The documents below are the place to track changes for this. If it is not reflected here - it is not happening ;) (for now)

Click to expand OpenAPI (copy to https://editor-next.swagger.io/ for your convenience)
openapi: 3.0.3
info:
  title: MII Feasibility Backend REST API - Terminology Search Draft
  description: todo
  contact:
    email: noreply@todo.de
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: 0.0.1
externalDocs:
  description: Check out the github repository
  url: https://github.com/medizininformatik-initiative/feasibility-backend
servers:
  - url: https://to.be.defined
    variables:
      basePath:
        default: /
tags:
  - name: terminology
    description: operations on the terminology
  - name: codeable concepts
    description: operations on codeable concepts
paths:
  /terminology/search/filter:
    get:
      tags:
        - terminology
      summary: "Get the list of available filters"
      operationId: "getFilters"
      responses:
        200:
          description: Ok, return the list of available filters
          content:
            application/json:
              schema:
                type: "array"
                items:
                  $ref: "#/components/schemas/Filter"
  /terminology/entry/search:
    get:
      tags:
        - terminology
      summary: "Parametrized search in the configured elastic search service."
      operationId: "search"
      parameters:
        - name: searchterm
          in: query
          description: The term to search for. In case of an empty searchterm, return the first page of the whole index, sorted alphabetically
          schema:
            type: "string"
          example: Diabetes Mellitus
        - name: contexts
          in: query
          description: Limit the search to any of the given contexts
          schema:
            type: array
            items:
              type: string
              example: Diagnosis
          style: form
          explode: false
        - name: terminologies
          in: query
          description: Limit the search to a any of the given terminologies
          schema:
            type: array
            items:
              type: string
              example: ICD10
          style: form
          explode: false
        - name: kds-modules
          in: query
          description: Limit the search to any of the given KDS modules
          schema:
            type: array
            items:
              type: string
              example: Condition
          style: form
          explode: false
        - name: criteria-sets
          in: query
          description: Limit the search to certain criteria sets (specified via url)
          schema:
            type: array
            items:
              type: string
              example: http://fhir.de/CodeSystem/bfarm/icd-10-gm
          style: form
          explode: false
        - name: availability
          in: query
          description: Limit the search to available items? (Maybe better invert this one to make this the default?)
          schema:
            type: boolean
          example: true
        - name: page-size
          in: query
          description: How many results shall be returned per page
          schema:
            type: integer
          example: 10
        - name: page
          in: query
          description: Which page shall be returned
          schema:
            type: integer
          example: 42
      responses:
        200:
          description: Ok, return the list of results for the search
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ElasticSearchResult"
  /terminology/entry/{id}/relations:
    get:
      tags:
        - terminology
      summary: "Get the detailed entry for a criterion, containing children and translations"
      operationId: "getEntryById"
      parameters:
        - name: id
          in: path
          description: The id (contextualized termcode hash) of the entry that shall be retrieved
          required: true
          schema:
            type: string
            example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
      responses:
        200:
          description: Entry found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ElasticSearchResultEntryWithRelations'
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Entry not found
  /terminology/entry/{id}:
    get:
      tags:
        - terminology
      summary: "Get the detailed entry for a criterion, containing children and translations"
      description: "This should be in the getEntryById call, but for better distinction between the return values it is listed seperately here"
      operationId: "getEntriesById"
      parameters:
        - name: id
          in: path
          description: The ids (contextualized termcode hash) of the entries that shall be retrieved
          required: true
          schema:
            type: string
            example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
      responses:
        200:
          description: Entry found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ElasticSearchResultEntry'
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Entry not found
  /terminology/criteria-profile-data:
    get:
      tags:
        - terminology
      summary: "Get the profile data for criteria, containing uiProfile context and termCodes"
      description: "This should return all the information needed to build criteria in the frontend."
      operationId: "getEntriesByIdsWithDetail"
      parameters:
        - name: ids
          in: query
          style: form
          explode: false
          description: "A comma-separated list of IDs (contextualized termcode hashes) of the entries that shall be retrieved."
          required: true
          schema:
            type: string
            example: "203e04cd-4f0a-321b-b1ad-9ec6d211e0a8,203e04cd-4f0a-321b-b1ad-9ec6d211e0a9"
      responses:
        200:
          description: "Entries found. May contain empty entries if some were not found."
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CriteriaProfileData'
        401:
          description: "Unauthorized - please login first."
        403:
          description: "Forbidden - insufficient access rights."
  /codeable-concept/entry/search:
    get:
      tags:
        - codeable concepts
      summary: Search for codeable concepts by code or display. Optionally filter by value sets
      operationId: searchCodeableConcepts
      parameters: 
        - name: searchterm
          in: query
          description: The term to search for. In case of an empty searchterm, return the first page of the whole index, sorted alphabetically
          schema:
            type: "string"
          example: Diabetes Mellitus
        - name: value-sets
          in: query
          description: Limit the search to certain value sets (specified via url)
          schema:
            type: array
            items:
              type: string
              example: http://fhir.de/CodeSystem/bfarm/icd-10-gm
          style: form
          explode: false
        - name: page-size
          in: query
          description: How many results shall be returned per page
          schema:
            type: integer
          example: 10
        - name: page
          in: query
          description: Which page shall be returned
          schema:
            type: integer
          example: 42
      responses:
        200:
          description: Ok, return the page of results
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CodeableConceptSearchResult"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
  /codeable-concept/entry/{id}:
    get:
      tags:
        - codeable concepts
      summary: Search for codeable concepts by code or display. Optionally filter by value sets
      operationId: getCodeableConceptByCode
      parameters: 
        - name: id
          in: path
          description: The id (contextualized termcode hash) of the entry that shall be retrieved
          required: true
          schema:
            type: string
            example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
      responses:
        200:
          description: Ok, return the codeable concept
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TermCode"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Entry not found

components:
  schemas:
    CodeableConceptSearchResult:
      type: object
      properties:
        totalHits:
          type: integer
          example: 42
        results:
          type: array
          items:
            $ref: "#/components/schemas/TermCode"
    ElasticSearchResult:
      type: object
      properties:
        totalHits:
          type: integer
          example: 42
        results:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchResultEntry"
    ElasticSearchResultEntryWithRelations:
      type: object
      properties:
        translations:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchTranslationEntry"
        parents:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
        children:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
        relatedTerms:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
    ElasticSearchResultEntry:
      type: object
      properties:
        name:
          type: string
          example: Diabetes Mellitus
        id:
          type: string
          format: uuid
          example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
        availability:
          description: Not sure if we want this as numeric value, percentage or just boolean?
          type: integer
          minimum: 0
          example: 119578
        context:
          type: string
          example: Diagnosis
        terminology:
          type: string
          example: icd-10
        termcode:
          type: string
          example: E10-E14
        kdsModule:
          type: string
          example: Condition
        selectable:
          type: boolean
          example: true
    ElasticSearchTranslationEntry:
      type: object
      properties:
        lang:
          type: string
          example: en
        value:
          type: string
          example: Diabetes Mellitus
    ElasticSearchRelationEntry:
      type: object
      properties:
        name:
          type: string
          example: Endokrine, Ernährungs- und Stoffwechselerkrankungen
        contextualizedTermcodeHash:
          type: string
          example: c55d0d62-6c47-30b0-94b2-afa383ce35f7
    CriteriaProfileData:
      type: object
      properties:
        id:
          type: string
          format: uuid
        uiprofile:
          type: array
          items:
            $ref: "#/components/schemas/UiProfileEntry"
        termCodes:
          type: array
          items:
            $ref: "#/components/schemas/TermCode"
        context:
          $ref: "#/components/schemas/TermCode"
  
    Filter:
      type: object
      properties:
        name:
          type: string
          example: terminology
        type:
          type: string
          example: selectable-concept
        values:
          type: array
          items:
            $ref: "#/components/schemas/FilterValue"
    FilterValue:
      type: object
      properties:
        label:
          type: string
          example: http://fhir.de/CodeSystem/bfarm/ops
        count:
          type: integer
          example: 42
    TermCode:
      type: object
      properties:
        code:
          type: string
          example: "E14.0"
        system:
          type: string
          example: "http://fhir.de/CodeSystem/bfarm/icd-10-gm"
        version:
          type: string
          example: "2023"
        display:
          type: string
          example: "Diabetes mellitus"
    UiProfileEntry:
      type: object
      properties:
        attributeDefinitions:
          type: array
          items:
            $ref: "#/components/schemas/AttributeDefinition"
        name:
          type: string
          example: "Diagnose"
        timeRestrictionAllowed:
          type: boolean
          example: false
        valueDefinition:
          type: string
    Unit:
      type: object
      properties:
        code:
          type: string
        display:
          type: string
    AttributeDefinition:
      type: object
      properties:
        allowedUnits:
          type: array
          items:
            $ref: "#/components/schemas/Unit"
        attributeCode:
          $ref: "#/components/schemas/TermCode"
        max:
          type: number
          example: null
        min:
          type: number
          example: null
        optional:
          type: boolean
          example: true
        precision:
          type: number
          example: 1
        referencedCriteriaSet:
          type: string
          example: "http://fdpg.mii.cds/CriteriaSet/Diagnose/icd-10-gm"
        referencedValueSet:
          type: string
          example: "http://hl7.org/fhir/sid/icd-o-3"
        type:
          type: string
          example: "reference"
Click to expand Elastic Search index for ontology
{
  "settings": {
    "analysis": {
      "tokenizer": {
        "edge_ngram_tokenizer": {
          "type": "edge_ngram",
          "min_gram": 1,
          "max_gram": 20,
          "token_chars": [
            "letter",
            "digit"
          ]
        }
      },
      "analyzer": {
        "edge_ngram_analyzer": {
          "type": "custom",
          "tokenizer": "edge_ngram_tokenizer",
          "filter": [
            "lowercase"
          ]
        },
        "lowercase_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "availability": {
        "type": "long",
        "index": false
      },
      "children": {
        "properties": {
          "contextualized_termcode_hash": {
            "type": "text",
            "index": false
          },
          "name": {
            "type": "text",
            "index": false
          }
        }
      },
      "context": {
        "properties": {
          "code": {
            "type": "keyword"
          },
          "display": {
            "type": "keyword"
          },
          "system": {
            "type": "keyword"
          },
          "version": {
            "type": "keyword"
          }
        }
      },
      "criteria_sets": {
        "type": "keyword"
      },
      "kds_module": {
        "type": "keyword"
      },
      "name": {
        "type": "text",
        "analyzer": "edge_ngram_analyzer",
        "search_analyzer": "lowercase_analyzer"
      },
      "parents": {
        "properties": {
          "contextualized_termcode_hash": {
            "type": "text",
            "index": false
          },
          "name": {
            "type": "text",
            "index": false
          }
        }
      },
      "related_terms": {
        "properties": {
          "contextualized_termcode_hash": {
            "type": "text",
            "index": false
          },
          "name": {
            "type": "text",
            "index": false
          }
        }
      },
      "selectable": {
        "type": "boolean"
      },
      "termcode": {
        "type": "text",
        "analyzer": "edge_ngram_analyzer",
        "search_analyzer": "lowercase_analyzer"
      },
      "termcodes": {
        "properties": {
          "code": {
            "type": "text",
            "index": false
          },
          "display": {
            "type": "text",
            "index": false
          },
          "system": {
            "type": "text",
            "index": false
          },
          "version": {
            "type": "text",
            "index": false
          }
        }
      },
      "terminology": {
        "type": "keyword"
      },
      "translations": {
        "properties": {
          "lang": {
            "type": "text",
            "index": false
          },
          "value": {
            "type": "text",
            "index": false
          }
        }
      }
    }
  }
}
Click to expand Elastic Search index for codeable concepts
{
    "settings": {
    "analysis": {
      "tokenizer": {
        "edge_ngram_tokenizer": {
          "type": "edge_ngram",
          "min_gram": 1,
          "max_gram": 20,
          "token_chars": [
            "letter",
            "digit"
          ]
        }
      },
      "analyzer": {
        "edge_ngram_analyzer": {
          "type": "custom",
          "tokenizer": "edge_ngram_tokenizer",
          "filter": [
            "lowercase"
          ]
        },
        "lowercase_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "termcode": {
        "properties": {
          "code": {
            "type": "text",
            "analyzer": "edge_ngram_analyzer",
            "search_analyzer": "lowercase_analyzer"
          },
          "display": {
            "type": "text",
            "analyzer": "edge_ngram_analyzer",
            "search_analyzer": "lowercase_analyzer"
          },
          "system": {
            "type": "text",
            "index": false
          },
          "version": {
            "type": "long",
            "index": false
          }
        }
      },
      "value_sets": {
        "type": "keyword"
      }
    }
  }
}
@michael-82 michael-82 added the enhancement New feature or request label Feb 6, 2024
@michael-82
Copy link

The first 3-ish ideas for json objects to store in elastic (which would have to be generated by the ontology generator or by another tool in cooperation with the ontology generator for that matter) are as follows.

Please consider this as some sort of "mix and match" - I didn't want to include each and every permutation of the options.

The "contextualized-termcode-hash" in each of those examples would be removed from the json and used as id in elastic search (or maybe it can also stay in the json, but I don't see any benefit from it)

Option 1

This is pretty verbose and contains the full information needed to a) display and b) load any relatives. Availability is a numeric value (either absolute or relative?) - not sure if this is a) possible b) allowed c) desired

{
  "name": "Diabetes Mellitus",
  "contextualized-termcode-hash": "203e04cd-4f0a-321b-b1ad-9ec6d211e0a8",
  "availability": "96",
  "domain": "Diagnosis",
  "terminology": "icd-10",
  "termcode": "E10-E14",
  "kds-module": "Condition",
  "translations" : [
    {
      "lang": "de",
      "value": "Diabetes Mellitus"
    },
    {
      "lang": "en-UK",
      "value": "Diabetes Mellitus"
    }
  ],
  "parents" : [
    {
      "name": "Endokrine, Ernährungs- und Stoffwechselerkrankungen",
      "contextualized-termcode-hash": "c55d0d62-6c47-30b0-94b2-afa383ce35f7"
    }
  ],
  "children": [
    {
      "name": "Diabetes Mellitus, Typ 1",
      "contextualized-termcode-hash": "b303cc1c-0776-3d78-9f18-98847173a73d"
    },
    {
      "name": "Diabetes Mellitus, Typ 2",
      "contextualized-termcode-hash": "29451c0c-e26d-3d43-9b74-6e43230ac9f5"
    }
  ]
}

Option 2

This limits the information about the relatives to their ids. It also groups the terminology parts to an object (good ideas for a name are welcome). The translations part is also a bit condensed, but contain the information about which of those are verified. Availability is restricted to a boolean

{
  "name": "Diabetes Mellitus",
  "contextualized-termcode-hash": "203e04cd-4f0a-321b-b1ad-9ec6d211e0a8",
  "availability": true,
  "to-be-named": {
    "domain": "Diagnosis",
    "terminology": "icd-10",
    "termcode": "E10-E14",
    "kds-module": "Condition"
  },
  "translations" : [
    {
      "de": "Diabetes Mellitus",
      "verified": false
    },
    {
      "en-UK": "Diabetes Mellitus",
      "verified": true
    }
  ],
  "parents" : [
      "c55d0d62-6c47-30b0-94b2-afa383ce35f7"
  ],
  "children": [
      "b303cc1c-0776-3d78-9f18-98847173a73d",
      "29451c0c-e26d-3d43-9b74-6e43230ac9f5"
  ]
}

Option 3

This removes all information about relatives. This information would have to be gathered from the backend and injected before sending back to the gui (or who/whatever uses the rest api). The language contains information about a preferred translation (not really sure if this should be in elastic search). The "name" part is lacking, because it can be retrieved from the translations array and it would be up to the gui which one to display (based on browser language or user setting?)

{
  "contextualized-termcode-hash": "203e04cd-4f0a-321b-b1ad-9ec6d211e0a8",
  "availability": true,
  "to-be-named": {
    "domain": "Diagnosis",
    "terminology": "icd-10",
    "termcode": "E10-E14",
    "kds-module": "Condition"
  },
  "translations" : [
    {
      "lang": "de",
      "value": "Diabetes Mellitus",
      "verified": true,
      "preferred": true
    },
    {
      "lang": "en-UK",
      "value": "Diabetes Mellitus",
      "verified": false
    }
  ]
}

@michael-82
Copy link

michael-82 commented Feb 6, 2024

As a proposal for the API, ideally just paste the following to https://editor-next.swagger.io . This also is one example, which would be mutable, depending on what we choose to store in elastic.

There is once more a placeholder for parameters we might want to add, like limiting to a certain amount of results, or giving an offset to enable pagination, or maybe a minimum required score for a result to be included.

It would also be an option to use a json request body for the query instead of query parameters.

Click to expand OpenAPI code
openapi: 3.0.3
info:
  title: MII Feasibility Backend REST API - Terminology Search Draft
  description: todo
  contact:
    email: noreply@todo.de
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: 0.0.1
externalDocs:
  description: Check out the github repository
  url: https://github.com/medizininformatik-initiative/feasibility-backend
servers:
  - url: https://to.be.defined
    variables:
      basePath:
        default: /
tags:
  - name: terminology
    description: operations on the terminology
paths:
  /terminology/search:
    get:
      tags:
        - terminology
      summary: "Parametrized search in the configured elastic search service."
      operationId: "search"
      parameters:
        - name: query
          in: query
          description: The term to search for
          schema:
            type: "string"
          example: Diabetes Mellitus
        - name: placeholder
          in: query
          description: Maybe include limit/offset/min-score?
          schema:
            type: "string"
          example: example
        - name: domain
          in: query
          description: Limit the search to a given domain (or domains?)
          schema:
            type: "string"
          example: Diagnosis
        - name: terminology
          in: query
          description: Limit the search to a given terminology (or terminologies?)
          schema:
            type: "string"
          example: ICD10
        - name: kds
          in: query
          description: Limit the search to a given KDS module (or modules?)
          schema:
            type: "string"
          example: Condition
        - name: availability
          in: query
          description: Limit the search to available items? (Maybe better invert this one to make this the default?)
          schema:
            type: boolean
          example: true
      responses:
        200:
          description: Ok, return the list of results (maybe limited/offset - to be decided) for the search
          content:
            application/json:
              schema:
                type: "array"
                items:
                  $ref: "#/components/schemas/ElasticSearchResult"
components:
  schemas:
    ElasticSearchResult:
      type: object
      properties:
        totalHits:
          type: integer
          example: 42
        results:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchResultEntry"
    ElasticSearchResultEntry:
      type: object
      properties:
        name:
          type: string
          example: Diabetes Mellitus
        contextualizedTermcodeHash:
          type: string
          format: uuid
          example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
        availability:
          description: Not sure if we want this as numeric value, percentage or just boolean?
          type: integer
          minimum: 0
          maximum: 100
          example: 94
        domain:
          type: string
          example: Diagnosis
        terminology:
          type: string
          example: icd-10
        termcode:
          type: string
          example: E10-E14
        kdsModule:
          type: string
          example: Condition
        translations:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchTranslationEntry"
        parents:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
        children:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
    ElasticSearchTranslationEntry:
      type: object
      properties:
        lang:
          type: string
          example: en
        value:
          type: string
          example: Diabetes Mellitus
    ElasticSearchRelationEntry:
      type: object
      properties:
        name:
          type: string
          example: Endokrine, Ernährungs- und Stoffwechselerkrankungen
        contextualizedTermcodeHash:
          type: string
          example: c55d0d62-6c47-30b0-94b2-afa383ce35f7

@michael-82
Copy link

michael-82 commented May 15, 2024

Following a discussion between @juliangruendner @Shayan1375 @thkoehler11 and myself from today (2024-05-15), the following has been decided:

Elasticsearch

Data Storage

Please note that the object below is NOT necessarily what will be returned to the frontend. For that part, look below in the OpenAPI code.

Objects will be stored in elastic search as suggested in option 1 above, with the minor change that domain will be renamed to context, resulting in:

Click to expand JSON
{
  "name": "Diabetes Mellitus",
  "contextualized-termcode-hash": "203e04cd-4f0a-321b-b1ad-9ec6d211e0a8",
  "availability": "96",
  "context": "Diagnosis",
  "terminology": "icd-10",
  "termcode": "E10-E14",
  "kds-module": "Condition",
  "translations" : [
    {
      "lang": "de",
      "value": "Diabetes Mellitus"
    },
    {
      "lang": "en-UK",
      "value": "Diabetes Mellitus"
    }
  ],
  "parents" : [
    {
      "name": "Endokrine, Ernährungs- und Stoffwechselerkrankungen",
      "contextualized-termcode-hash": "c55d0d62-6c47-30b0-94b2-afa383ce35f7"
    }
  ],
  "children": [
    {
      "name": "Diabetes Mellitus, Typ 1",
      "contextualized-termcode-hash": "b303cc1c-0776-3d78-9f18-98847173a73d"
    },
    {
      "name": "Diabetes Mellitus, Typ 2",
      "contextualized-termcode-hash": "29451c0c-e26d-3d43-9b74-6e43230ac9f5"
    }
  ],
  "relatedTerms": [
    {
      "name": "foo",
      "contextualized-termcode-hash": "81e98694-bb61-4e1f-844e-399806b67b08"
    },
    {
      "name": "bar",
      "contextualized-termcode-hash": "644de523-636a-4afe-9ade-997db8487f81"
    }
  ]
}

For now, availability will be stored as an absolute numeric value. There is some optimism that this will be allowed to display, since it will have no site-correlation as it is only an aggregated number over all sites (however, there is always a chance that it will have to be removed later)

Search behaviour

For now, a search query will only check the fields termcode and name. In further iterations, the translations might be included (maybe prioritized by accept-language priority?)

API frontend <-> backend

The API will be modified from the former suggestion, following a refined proposal for the frontend.

TL;DR:

  • pagination for search results
  • add endpoint to provide all available filters
  • the search endpoint will not provide parents and/or children, and no translations
  • an additional endpoint will be added to retrieve a criterion by id (which is the contextualized-termcode-hash)
  • if there are criteria with multiple termcodes, always take the first one.

Possible additions to do later:

  • add the information how a search result would change if a filter would be applied
  • the gui concept shows "additional information" which could e.g. offer a link to the icd 10 terminology or snomed, depending on the criterion. This is not fully defined for now, but probably could be another table (or 2) in the database and should not be a big issue for the api here

OpenAPI

With the aforementioned changes...just copy the following to https://editor-next.swagger.io/

Click to expand OpenAPI code
openapi: 3.0.3
info:
  title: MII Feasibility Backend REST API - Terminology Search Draft
  description: todo
  contact:
    email: noreply@todo.de
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: 0.0.1
externalDocs:
  description: Check out the github repository
  url: https://github.com/medizininformatik-initiative/feasibility-backend
servers:
  - url: https://to.be.defined
    variables:
      basePath:
        default: /
tags:
  - name: terminology
    description: operations on the terminology
paths:
  /terminology/search/filter:
    get:
      tags:
        - terminology
      summary: "Get the list of available filters"
      operationId: "getFilters"
      responses:
        200:
          description: Ok, return the list of available filters
          content:
            application/json:
              schema:
                type: "array"
                items:
                  $ref: "#/components/schemas/Filter"
  /terminology/search:
    get:
      tags:
        - terminology
      summary: "Parametrized search in the configured elastic search service."
      operationId: "search"
      parameters:
        - name: searchterm
          in: query
          description: The term to search for
          schema:
            type: "string"
          example: Diabetes Mellitus
        - name: context
          in: query
          description: Limit the search to a given context (or contexts?)
          schema:
            type: "string"
          example: Diagnosis
        - name: terminology
          in: query
          description: Limit the search to a given terminology (or terminologies?)
          schema:
            type: "string"
          example: ICD10
        - name: kds
          in: query
          description: Limit the search to a given KDS module (or modules?)
          schema:
            type: "string"
          example: Condition
        - name: availability
          in: query
          description: Limit the search to available items? (Maybe better invert this one to make this the default?)
          schema:
            type: boolean
          example: true
        - name: limit
          in: query
          description: How many results shall be returned
          schema:
            type: integer
          example: 10
        - name: offset
          in: query
          description: What should be the index of the first item to be displayed
          schema:
            type: integer
          example: 100
      responses:
        200:
          description: Ok, return the list of results (maybe limited/offset - to be decided) for the search
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ElasticSearchResult"
  /terminology/search/{id}:
    get:
      tags:
        - terminology
      summary: "Get the detailed entry for a criterion, containing children and translations"
      operationId: "getEntryById"
      parameters:
        - name: id
          in: path
          description: The id (contextualized termcode hash) of the entry that shall be retrieved
          required: true
          schema:
            type: string
            example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
      responses:
        200:
          description: Entry found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ElasticSearchResultEntryWithRelations'
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Entry not found
components:
  schemas:
    ElasticSearchResult:
      type: object
      properties:
        totalHits:
          type: integer
          example: 42
        results:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchResultEntry"
    ElasticSearchResultEntryWithRelations:
      type: object
      properties:
        name:
          type: string
          example: Diabetes Mellitus
        contextualizedTermcodeHash:
          type: string
          format: uuid
          example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
        availability:
          description: Not sure if we want this as numeric value, percentage or just boolean?
          type: integer
          minimum: 0
          maximum: 100
          example: 94
        context:
          type: string
          example: Diagnosis
        terminology:
          type: string
          example: icd-10
        termcode:
          type: string
          example: E10-E14
        kdsModule:
          type: string
          example: Condition
        translations:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchTranslationEntry"
        parents:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
        children:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
        relatedTerms:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
    ElasticSearchResultEntry:
      type: object
      properties:
        name:
          type: string
          example: Diabetes Mellitus
        contextualizedTermcodeHash:
          type: string
          format: uuid
          example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
        availability:
          description: Not sure if we want this as numeric value, percentage or just boolean?
          type: integer
          minimum: 0
          example: 119578
        context:
          type: string
          example: Diagnosis
        terminology:
          type: string
          example: icd-10
        termcode:
          type: string
          example: E10-E14
        kdsModule:
          type: string
          example: Condition
    ElasticSearchTranslationEntry:
      type: object
      properties:
        lang:
          type: string
          example: en
        value:
          type: string
          example: Diabetes Mellitus
    ElasticSearchRelationEntry:
      type: object
      properties:
        name:
          type: string
          example: Endokrine, Ernährungs- und Stoffwechselerkrankungen
        contextualizedTermcodeHash:
          type: string
          example: c55d0d62-6c47-30b0-94b2-afa383ce35f7
    Filter:
      type: object
      properties:
        name:
          type: string
          example: Terminology
        values:
          type: array
          items:
            $ref: "#/components/schemas/FilterValue"
          example:
            - ICD10
            - SNOMED
            - LOINC
    FilterValue:
      type: string
      example: "icd10"

@michael-82
Copy link

michael-82 commented Jun 3, 2024

Following another discussion on 2024-05-29, we decided to combine some of the former endpoints in order to reduce the amount of calls. The legacy calls to the backend to get entries from the ui tree files will be removed. The ui profiles will be included in the regular call to retrieve an entry. This means an additional call to the database when retrieving an entry, but is more efficient than having two seperate rest calls for that.
Other notable changes are the addition of the selectable attribute and the addition of the complete context and term codes. This is all reflected in the swagger file below. The stored objects in elastic search will also change accordingly.

Click to expand JSON
{
  "name": "Diabetes Mellitus",
  "contextualized-termcode-hash": "203e04cd-4f0a-321b-b1ad-9ec6d211e0a8",
  "availability": 96,
  "terminology": "http://fhir.de/CodeSystem/bfarm/icd-10-gm",
  "termCode": "E10-E14",
  "kds-module": "Condition",
  "selectable": true,
  "context": {
      "code": "Diagnose",
      "display": "Diagnose",
      "system": "fdpg.mii.cds",
      "version": "1.0.0"
  },
  "termCodes": [
    {
        "code": "E10-E14",
        "display": "Diabetes mellitus",
        "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm",
        "version": "2023"
    }
  ],
  "translations" : [
    {
      "lang": "de",
      "value": "Diabetes Mellitus"
    },
    {
      "lang": "en-UK",
      "value": "Diabetes Mellitus"
    }
  ],
  "parents" : [
    {
      "name": "Endokrine, Ernährungs- und Stoffwechselerkrankungen",
      "contextualized-termcode-hash": "c55d0d62-6c47-30b0-94b2-afa383ce35f7"
    }
  ],
  "children": [
    {
      "name": "Diabetes Mellitus, Typ 1",
      "contextualized-termcode-hash": "b303cc1c-0776-3d78-9f18-98847173a73d"
    },
    {
      "name": "Diabetes Mellitus, Typ 2",
      "contextualized-termcode-hash": "29451c0c-e26d-3d43-9b74-6e43230ac9f5"
    }
  ],
  "relatedTerms": [
    {
      "name": "foo",
      "contextualized-termcode-hash": "81e98694-bb61-4e1f-844e-399806b67b08"
    },
    {
      "name": "bar",
      "contextualized-termcode-hash": "644de523-636a-4afe-9ade-997db8487f81"
    }
  ]
}
Click to expand OpenAPI
openapi: 3.0.3
info:
  title: MII Feasibility Backend REST API - Terminology Search Draft
  description: todo
  contact:
    email: noreply@todo.de
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: 0.0.1
externalDocs:
  description: Check out the github repository
  url: https://github.com/medizininformatik-initiative/feasibility-backend
servers:
  - url: https://to.be.defined
    variables:
      basePath:
        default: /
tags:
  - name: terminology
    description: operations on the terminology
paths:
  /terminology/search/filter:
    get:
      tags:
        - terminology
      summary: "Get the list of available filters"
      operationId: "getFilters"
      responses:
        200:
          description: Ok, return the list of available filters
          content:
            application/json:
              schema:
                type: "array"
                items:
                  $ref: "#/components/schemas/Filter"
  /terminology/search:
    get:
      tags:
        - terminology
      summary: "Parametrized search in the configured elastic search service."
      operationId: "search"
      parameters:
        - name: searchterm
          in: query
          description: The term to search for
          schema:
            type: "string"
          example: Diabetes Mellitus
        - name: context
          in: query
          description: Limit the search to a given context (or contexts?)
          schema:
            type: "string"
          example: Diagnosis
        - name: terminology
          in: query
          description: Limit the search to a given terminology (or terminologies?)
          schema:
            type: "string"
          example: ICD10
        - name: kds
          in: query
          description: Limit the search to a given KDS module (or modules?)
          schema:
            type: "string"
          example: Condition
        - name: availability
          in: query
          description: Limit the search to available items? (Maybe better invert this one to make this the default?)
          schema:
            type: boolean
          example: true
        - name: pageSize
          in: query
          description: How many results shall be returned per page
          schema:
            type: integer
          example: 10
        - name: page
          in: query
          description: Which page shall be returned
          schema:
            type: integer
          example: 42
      responses:
        200:
          description: Ok, return the list of results (maybe limited/offset - to be decided) for the search
          content:
            application/json:
              schema:
                type: "array"
                items:
                  $ref: "#/components/schemas/ElasticSearchResult"
  /terminology/entry/{id}:
    get:
      tags:
        - terminology
      summary: "Get the detailed entry for a criterion, containing children and translations"
      operationId: "getEntryById"
      parameters:
        - name: id
          in: path
          description: The id (contextualized termcode hash) of the entry that shall be retrieved
          required: true
          schema:
            type: string
            example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
      responses:
        200:
          description: Entry found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ElasticSearchResultEntry'
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Entry not found
  /terminology/entry/{id}?detail=true:
    get:
      tags:
        - terminology
      summary: "Get the detailed entry for a criterion, containing children and translations"
      description: "This should be in the getEntryById call, but for better distinction between the return values it is listed seperately here"
      operationId: "getEntryByIdWithDetail"
      parameters:
        - name: id
          in: path
          description: The id (contextualized termcode hash) of the entry that shall be retrieved
          required: true
          schema:
            type: string
            example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
      responses:
        200:
          description: Entry found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ElasticSearchResultEntryWithRelations'
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Entry not found
components:
  schemas:
    ElasticSearchResult:
      type: object
      properties:
        totalHits:
          type: integer
          example: 42
        results:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchResultEntry"
    ElasticSearchResultEntryWithRelations:
      type: object
      properties:
        name:
          type: string
          example: Diabetes Mellitus
        id:
          type: string
          format: uuid
          example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
        availability:
          description: Not sure if we want this as numeric value, percentage or just boolean?
          type: integer
          minimum: 0
          maximum: 100
          example: 94
        terminology:
          type: string
          example: icd-10
        termcode:
          type: string
          example: E10-E14
        kdsModule:
          type: string
          example: Condition
        selectable:
          type: boolean
          example: false
        context:
          $ref: "#/components/schemas/TermCode"
        termCodes:
          type: array
          items:
            $ref: "#components/schemas/TermCode"
        translations:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchTranslationEntry"
        parents:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
        children:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
        relatedTerms:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
        uiprofile:
          $ref: "#/components/schemas/UiProfileEntry"
    ElasticSearchResultEntry:
      type: object
      properties:
        name:
          type: string
          example: Diabetes Mellitus
        id:
          type: string
          format: uuid
          example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
        availability:
          description: Not sure if we want this as numeric value, percentage or just boolean?
          type: integer
          minimum: 0
          example: 119578
        context:
          type: string
          example: Diagnosis
        terminology:
          type: string
          example: icd-10
        termcode:
          type: string
          example: E10-E14
        kdsModule:
          type: string
          example: Condition
        selectable:
          type: boolean
          example: true
    ElasticSearchTranslationEntry:
      type: object
      properties:
        lang:
          type: string
          example: en
        value:
          type: string
          example: Diabetes Mellitus
    ElasticSearchRelationEntry:
      type: object
      properties:
        name:
          type: string
          example: Endokrine, Ernährungs- und Stoffwechselerkrankungen
        contextualizedTermcodeHash:
          type: string
          example: c55d0d62-6c47-30b0-94b2-afa383ce35f7
    Filter:
      type: object
      properties:
        name:
          type: string
          example: Terminology
        values:
          type: array
          items:
            $ref: "#/components/schemas/FilterValue"
          example:
            - ICD10
            - SNOMED
            - LOINC
    FilterValue:
      type: string
      example: "icd10"
    TermCode:
      type: object
      properties:
        code:
          type: string
          example: "E14.0"
        system:
          type: string
          example: "http://fhir.de/CodeSystem/bfarm/icd-10-gm"
        version:
          type: string
          example: "2023"
        display:
          type: string
          example: "Diabetes mellitus"
    UiProfileEntry:
      type: object
      properties:
        attributeDefinitions:
          type: array
          items:
            $ref: "#/components/schemas/AttributeDefinition"
        name:
          type: string
          example: "Diagnose"
        timeRestrictionAllowed:
          type: boolean
          example: false
        valueDefinition:
          type: string
    Unit:
      type: object
      properties:
        code:
          type: string
        display:
          type: string
    AttributeDefinition:
      type: object
      properties:
        allowedUnits:
          type: array
          items:
            $ref: "#/components/schemas/Unit"
        attributeCode:
          $ref: "#/components/schemas/TermCode"
        max:
          type: number
          example: null
        min:
          type: number
          example: null
        optional:
          type: boolean
          example: true
        precision:
          type: number
          example: 1
        referenceCriteriaSet:
          type: string
          example: "http://fdpg.mii.cds/CriteriaSet/Diagnose/icd-10-gm"
        selectableConcepts:
          type: array
          items:
            $ref: "#/components/schemas/TermCode"
        type:
          type: string
          example: "reference"

@Shayan1375
Copy link

Additional Changes: New GET Endpoint for UI Profiles

After further discussion, we have decided to make additional changes. We will introduce a new GET endpoint:
GET /terminology/ui-profile?id=afd0b036-625a-3aa8-b639-9dc8c8fff0ff,9c45c2f1-1761-3daa-ad31-1ff8703ae846

Details:

  • The IDs of the selected elements will be sent to the backend to retrieve the UI profiles.

  • The IDs in the GET URL are just an example and will be sent separated by commas.

  • We have determined that the URL can have a maximum length of 2,048 characters, which corresponds to approximately 50 IDs that can be sent at one time.

  • If there are more IDs, the frontend must split them into multiple GET requests and wait for the results.

Example Response:
The response of the GET request is a list of objects containing an ID and the corresponding UI profile. This response is also just an example:

Click to expand JSON
{
  [
      {
          "id": "afd0b036-625a-3aa8-b639-9dc8c8fff0ff",
          "uiProfile": {
              "attributeDefinitions": [
                  {
                      "allowedUnits": [
                          {
                              "code": "string",
                              "display": "string"
                          }
                      ],
                      "attributeCode": {
                          "code": "E14.0",
                          "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm",
                          "version": "2023",
                          "display": "Diabetes mellitus"
                      },
                      "max": null,
                      "min": null,
                      "optional": true,
                      "precision": 1,
                      "referenceCriteriaSet": "http://fdpg.mii.cds/CriteriaSet/Diagnose/icd-10-gm",
                      "selectableConcepts": [
                          {
                              "code": "E14.0",
                              "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm",
                              "version": "2023",
                              "display": "Diabetes mellitus"
                          }
                      ],
                      "type": "reference"
                  }
              ],
              "name": "Diagnose",
              "timeRestrictionAllowed": false,
              "valueDefinition": "string"
          }
      },
      {
          "id": "9c45c2f1-1761-3daa-ad31-1ff8703ae846",
          "uiProfile": {
              "attributeDefinitions": [
                  {
                      "allowedUnits": [
                          {
                              "code": "string",
                              "display": "string"
                          }
                      ],
                      "attributeCode": {
                          "code": "E14.0",
                          "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm",
                          "version": "2023",
                          "display": "Diabetes mellitus"
                      },
                      "max": null,
                      "min": null,
                      "optional": true,
                      "precision": 1,
                      "referenceCriteriaSet": "http://fdpg.mii.cds/CriteriaSet/Diagnose/icd-10-gm",
                      "selectableConcepts": [
                          {
                              "code": "E14.0",
                              "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm",
                              "version": "2023",
                              "display": "Diabetes mellitus"
                          }
                      ],
                      "type": "reference"
                  }
              ],
              "name": "Diagnose",
              "timeRestrictionAllowed": false,
              "valueDefinition": "string"
          }
      }
  ]
}

This change means that when retrieving data from http://localhost:8090/api/v3/terminology/entries/5dfe270a-d520-1de8-24eb-19452f270561?detail=true, a UI profile will no longer be required in the response.

Click to expand JSON
{
  "id": "5dfe270a-d520-1de8-24eb-19452f270561",
  "name": "Angeborene Torsion des Ovars",
  "availability": 2915,
  "terminology": "http://fhir.de/CodeSystem/bfarm/icd-10-gm",
  "termCode": "Q50.2",
  "kdsModule": null,
  "translations": [],
  "parents": [
    {
      "name": "Angeborene Fehlbildungen der Ovarien, der Tubae uterinae und der Ligg. lata uteri",
      "id": "8b4035b0-a6d1-dadf-a423-d4af8383ae0b"
    }
  ],
  "children": [],
  "relatedTerms": [],
}

@michael-82
Copy link

michael-82 commented Jun 5, 2024

The response containing the list of ui profiles will be the array itself, not a json object containing the array as in the JSON posted above.

Click to expand JSON
[
    {
        "id": "afd0b036-625a-3aa8-b639-9dc8c8fff0ff",
        "uiProfile": {
            "attributeDefinitions": [
                {
                    "allowedUnits": [
                        {
                            "code": "string",
                            "display": "string"
                        }
                    ],
                    "attributeCode": {
                        "code": "E14.0",
                        "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm",
                        "version": "2023",
                        "display": "Diabetes mellitus"
                    },
                    "max": null,
                    "min": null,
                    "optional": true,
                    "precision": 1,
                    "referenceCriteriaSet": "http://fdpg.mii.cds/CriteriaSet/Diagnose/icd-10-gm",
                    "selectableConcepts": [
                        {
                            "code": "E14.0",
                            "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm",
                            "version": "2023",
                            "display": "Diabetes mellitus"
                        }
                    ],
                    "type": "reference"
                }
            ],
            "name": "Diagnose",
            "timeRestrictionAllowed": false,
            "valueDefinition": "string"
        }
    },
    {
        "id": "9c45c2f1-1761-3daa-ad31-1ff8703ae846",
        "uiProfile": {
            "attributeDefinitions": [
                {
                    "allowedUnits": [
                        {
                            "code": "string",
                            "display": "string"
                        }
                    ],
                    "attributeCode": {
                        "code": "E14.0",
                        "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm",
                        "version": "2023",
                        "display": "Diabetes mellitus"
                    },
                    "max": null,
                    "min": null,
                    "optional": true,
                    "precision": 1,
                    "referenceCriteriaSet": "http://fdpg.mii.cds/CriteriaSet/Diagnose/icd-10-gm",
                    "selectableConcepts": [
                        {
                            "code": "E14.0",
                            "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm",
                            "version": "2023",
                            "display": "Diabetes mellitus"
                        }
                    ],
                    "type": "reference"
                }
            ],
            "name": "Diagnose",
            "timeRestrictionAllowed": false,
            "valueDefinition": "string"
        }
    }
]

Also, the response to the entry with details will still contain the context and termcodes as objects like decided earlier. Only the uiprofile will be removed, resulting in the following:

Click to expand JSON
{
    "id": "5dfe270a-d520-1de8-24eb-19452f270561",
    "name": "Angeborene Torsion des Ovars",
    "availability": 2915,
    "terminology": "http://fhir.de/CodeSystem/bfarm/icd-10-gm",
    "termCode": "Q50.2",
    "kdsModule": null,
    "translations": [],
    "parents": [
        {
            "name": "Angeborene Fehlbildungen der Ovarien, der Tubae uterinae und der Ligg. lata uteri",
            "id": "8b4035b0-a6d1-dadf-a423-d4af8383ae0b"
        }
    ],
    "children": [],
    "relatedTerms": [],
    "context": {
        "code": "Diagnose",
        "system": "fdpg.mii.cds",
        "version": "1.0.0",
        "display": "Diagnose"
    },
    "termCodes": [
        {
            "code": "Q50.2",
            "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm",
            "version": "2023",
            "display": "Angeborene Torsion des Ovars"
        }
    ]
}

(Also, terminology will no longer be a URL in the future, but this is not relevant for this discussion.)

@Shayan1375
Copy link

Shayan1375 commented Jun 6, 2024

We've made updates to the endpoints and responses in the Swagger documentation to better align them with their names and expected responses.

We have introduced a new GET endpoint /terminology/criteria-profile-data/{ids}?= which returns the UiProfile, termCode, and context for a comma-separated list of IDs.

Additionally, we have established the endpoint /terminology/entry/{id}/relations which returns the parents, children, relatedTerms, and translations for a list entry. The id availability name terminology termCode kdsModule UiProfile context and termCodes have been removed from this endpoint. Therefore the endpoint /terminology/entry/{id}?detail=true becomes obselete.

The endpoint /terminology/search has been renamend to /terminology/entry/search
The revised Swagger documentation reflecting these changes can be found below.

Click to expand OpenAPI
openapi: 3.0.3
info:
  title: MII Feasibility Backend REST API - Terminology Search Draft
  description: todo
  contact:
    email: noreply@todo.de
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: 0.0.1
externalDocs:
  description: Check out the github repository
  url: https://github.com/medizininformatik-initiative/feasibility-backend
servers:
  - url: https://to.be.defined
    variables:
      basePath:
        default: /
tags:
  - name: terminology
    description: operations on the terminology
paths:
  /terminology/search/filter:
    get:
      tags:
        - terminology
      summary: "Get the list of available filters"
      operationId: "getFilters"
      responses:
        200:
          description: Ok, return the list of available filters
          content:
            application/json:
              schema:
                type: "array"
                items:
                  $ref: "#/components/schemas/Filter"
  /terminology/entry/search:
    get:
      tags:
        - terminology
      summary: "Parametrized search in the configured elastic search service."
      operationId: "search"
      parameters:
        - name: searchterm
          in: query
          description: The term to search for
          schema:
            type: "string"
          example: Diabetes Mellitus
        - name: context
          in: query
          description: Limit the search to a given context (or contexts?)
          schema:
            type: "string"
          example: Diagnosis
        - name: terminology
          in: query
          description: Limit the search to a given terminology (or terminologies?)
          schema:
            type: "string"
          example: ICD10
        - name: kds
          in: query
          description: Limit the search to a given KDS module (or modules?)
          schema:
            type: "string"
          example: Condition
        - name: availability
          in: query
          description: Limit the search to available items? (Maybe better invert this one to make this the default?)
          schema:
            type: boolean
          example: true
        - name: pageSize
          in: query
          description: How many results shall be returned per page
          schema:
            type: integer
          example: 10
        - name: page
          in: query
          description: Which page shall be returned
          schema:
            type: integer
          example: 42
      responses:
        200:
          description: Ok, return the list of results (maybe limited/offset - to be decided) for the search
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ElasticSearchResult"
  /terminology/entry/{id}/relations:
    get:
      tags:
        - terminology
      summary: "Get the detailed entry for a criterion, containing children and translations"
      operationId: "getEntryById"
      parameters:
        - name: id
          in: path
          description: The id (contextualized termcode hash) of the entry that shall be retrieved
          required: true
          schema:
            type: string
            example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
      responses:
        200:
          description: Entry found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ElasticSearchResultEntryWithRelations'
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Entry not found
  /terminology/entry/{id}:
    get:
      tags:
        - terminology
      summary: "Get the detailed entry for a criterion, containing children and translations"
      description: "This should be in the getEntryById call, but for better distinction between the return values it is listed seperately here"
      operationId: "getEntriesById"
      parameters:
        - name: id
          in: path
          description: The ids (contextualized termcode hash) of the entries that shall be retrieved
          required: true
          schema:
            type: string
            example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
      responses:
        200:
          description: Entry found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ElasticSearchResultEntry'
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Entry not found
  /terminology/criteria-profile-data:
    get:
      tags:
        - terminology
      summary: "Get the profile data for criteria, containing uiProfile context and termCodes"
      description: "This should return all the information needed to build criteria in the frontend."
      operationId: "getEntriesByIdsWithDetail"
      parameters:
        - name: ids
          in: query
          style: form
          explode: false
          description: "A comma-separated list of IDs (contextualized termcode hashes) of the entries that shall be retrieved."
          required: true
          schema:
            type: string
            example: "203e04cd-4f0a-321b-b1ad-9ec6d211e0a8,203e04cd-4f0a-321b-b1ad-9ec6d211e0a9"
      responses:
        200:
          description: "Entries found. May contain empty entries if some were not found."
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CriteriaProfileData'
        401:
          description: "Unauthorized - please login first."
        403:
          description: "Forbidden - insufficient access rights."

components:
  schemas:
    ElasticSearchResult:
      type: object
      properties:
        totalHits:
          type: integer
          example: 42
        results:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchResultEntry"
    ElasticSearchResultEntryWithRelations:
      type: object
      properties:
        translations:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchTranslationEntry"
        parents:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
        children:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
        relatedTerms:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
    ElasticSearchResultEntry:
      type: object
      properties:
        name:
          type: string
          example: Diabetes Mellitus
        id:
          type: string
          format: uuid
          example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
        availability:
          description: Not sure if we want this as numeric value, percentage or just boolean?
          type: integer
          minimum: 0
          example: 119578
        context:
          type: string
          example: Diagnosis
        terminology:
          type: string
          example: icd-10
        termcode:
          type: string
          example: E10-E14
        kdsModule:
          type: string
          example: Condition
        selectable:
          type: boolean
          example: true
    ElasticSearchTranslationEntry:
      type: object
      properties:
        lang:
          type: string
          example: en
        value:
          type: string
          example: Diabetes Mellitus
    ElasticSearchRelationEntry:
      type: object
      properties:
        name:
          type: string
          example: Endokrine, Ernährungs- und Stoffwechselerkrankungen
        contextualizedTermcodeHash:
          type: string
          example: c55d0d62-6c47-30b0-94b2-afa383ce35f7
    CriteriaProfileData:
      type: object
      properties:
        id:
          type: string
          format: uuid
        uiprofile:
          type: array
          items:
            $ref: "#/components/schemas/UiProfileEntry"
        termCodes:
          type: array
          items:
            $ref: "#/components/schemas/TermCode"
        context:
          $ref: "#/components/schemas/TermCode"
  
    Filter:
      type: object
      properties:
        name:
          type: string
          example: Terminology
        values:
          type: array
          items:
            $ref: "#/components/schemas/FilterValue"
          example:
            - ICD10
            - SNOMED
            - LOINC
    FilterValue:
      type: string
      example: "icd10"
    TermCode:
      type: object
      properties:
        code:
          type: string
          example: "E14.0"
        system:
          type: string
          example: "http://fhir.de/CodeSystem/bfarm/icd-10-gm"
        version:
          type: string
          example: "2023"
        display:
          type: string
          example: "Diabetes mellitus"
    UiProfileEntry:
      type: object
      properties:
        attributeDefinitions:
          type: array
          items:
            $ref: "#/components/schemas/AttributeDefinition"
        name:
          type: string
          example: "Diagnose"
        timeRestrictionAllowed:
          type: boolean
          example: false
        valueDefinition:
          type: string
    Unit:
      type: object
      properties:
        code:
          type: string
        display:
          type: string
    AttributeDefinition:
      type: object
      properties:
        allowedUnits:
          type: array
          items:
            $ref: "#/components/schemas/Unit"
        attributeCode:
          $ref: "#/components/schemas/TermCode"
        max:
          type: number
          example: null
        min:
          type: number
          example: null
        optional:
          type: boolean
          example: true
        precision:
          type: number
          example: 1
        referenceCriteriaSet:
          type: string
          example: "http://fdpg.mii.cds/CriteriaSet/Diagnose/icd-10-gm"
        selectableConcepts:
          type: array
          items:
            $ref: "#/components/schemas/TermCode"
        type:
          type: string
          example: "reference"

@michael-82
Copy link

michael-82 commented Jul 12, 2024

We discussed the new endpoints for searching in profiles. The first draft is below. Please comment @juliangruendner @Shayan1375 @thkoehler11

Click to expand OpenAPI fragment
openapi: 3.0.3
info:
  title: MII Feasibility Backend REST API - Terminology Search Draft
  description: todo
  contact:
    email: noreply@todo.de
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: 0.0.1
externalDocs:
  description: Check out the github repository
  url: https://github.com/medizininformatik-initiative/feasibility-backend
servers:
  - url: https://to.be.defined
    variables:
      basePath:
        default: /
tags:
  - name: tdb
    description: to be decided
paths:
  /terminology/healthrecord/tree:
    get:
      tags:
        - tbd
      responses:
        200:
          description: "Tree found and loaded. Will be delivered."
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/HealthRecordTree'
        401:
          description: "Unauthorized - please login first."
        403:
          description: "Forbidden - insufficient access rights."
  /terminology/healthrecord/profile:
    get:
      tags:
        - tbd
      parameters:
        - name: ids
          in: query
          style: form
          explode: false
          description: "A comma-separated list of IDs of the profiles that shall be retrieved."
          required: true
          schema:
            type: string
            example: "203e04cd-4f0a-321b-b1ad-9ec6d211e0a8,203e04cd-4f0a-321b-b1ad-9ec6d211e0a9"
      responses:
        200:
          description: "HealthRecord Profiles found - may contain empty entries"
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/HealthRecordProfileData'
        401:
          description: "Unauthorized - please login first."
        403:
          description: "Forbidden - insufficient access rights."
  /terminology/url-mapping:
    get:
      tags:
        - tbd
      responses:
        200:
          description: ok
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/UrlMapping'
              
components:
  schemas:
    UrlMapping:
      type: object
      properties:
        url:
          type: string
          format: url
          example: http://hl7.org/fhir/sid/icd-o-3
        display:
          type: string
          example: icd-o3
    HealthRecordProfileData:
      type: object
      properties:
        id:
          type: string
          format: uuid
        profiles:
          type: array
          items:
            $ref: '#/components/schemas/HealthRecordProfileEntry'
    HealthRecordProfileEntry:
      type: object
      properties:
        entry:
          description: this is to be decided by julian
          type: string
          format: json
    HealthRecordTree:
      type: object
      properties:
        entry:
          description: full json tree containing all profiles for now. might change if lazy loading or server-side filtering is required
          type: string
          format: json

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants