Table of Contents:
- Prerequisites
- Installation
- Data types
- Command line interface
- Server endpoints
- Add patient to server (/patient/add)
- Delete patient from server (/patient/delete/<patient_id>)
- Get server stats (/metrics)
- Get the list of connected nodes (/nodes)
- Send a match request to server (/match)
- Send a match request to external nodes (/match/external/<patient_id>)
- Show all matches for a given patient (/matches/<patient_id>)
- Patient matching algorithm
- Enabling matching notifications
To use this server you'll need to have a working instance of MongoDB. from the mongo shell you can create a database and an authenticated user to handle connections using this syntax:
use pmatcher
db.createUser(
{
user: "pmUser",
pwd: "pmPassword",
roles: [ "dbOwner" ]
}
)
After setting up the restricted access to the server you'll just have to launch the mongo demon using authentication:
mongod --auth --dbpath path_to_database_data
The phenotype scoring algorithm of patientMatcher is dependent on patient-similarity, which should be installed using this script:
pip install git+https://github.com/Clinical-Genomics/patient-similarity
After installing patient-similarity, clone patientMatcher repository from github using this command:
git clone https://github.com/Clinical-Genomics/patientMatcher.git
Change directory to the cloned folder and from there install the software using the following command:
pip install -e .
To customize the server configuration you'll need to edit the config.py file under the /instance folder. For testing purposes you can keep the default configuration values as they are, but keep in mind that you should adjust these numbers when in production.
To start the server run this command:
pmatcher run -h custom_host -p custom_port
Please note that the code is NOT guaranteed to be bug-free and it must be adapted to be used in production.
A simple Dockerfile has been included for testing purposes. It uses the sample instance/config.py
and
should not be used in production.
From the repo directory:
# note: docker does not allow upper case in image tags
$ docker build -t local/patientmatcher .
To run the image in the foreground use:
$ docker run -p 5000 --name patientMatcher local/patientmatcher
You can then curl localhost:5000/...
to the appropriate resources from another terminal. The database is
initialized with a test token (test_token
) that can be used. e.g.,
$ curl localhost:5000/metrics
To run with your own settings, mount an instance
directory containing a config.py
:
$ docker run -p 5000 -v /some/local/path/instance:/opt/patientMatcher/instance local/patientmatcher
This server implements the Matchmaker Exchange APIs. It accepts and returns patient data validated against the json schema defined in the MME reference-server project.
A list of available commands can be invoked by running the following command:
pmatcher
For testing purposes you can upload a list of 50 benchmarking patients. To add these patients to the database run the following command:
pmatcher add demodata --ensembl_genes
Please note that the list of benchmarking patients all gene ids are represented as HGNC gene symbols.
The command above, with the --ensembl_genes
option, will convert gene symbols to Ensembl ids, in accordance to the Ga4GH API: https://github.com/ga4gh/mme-apis/blob/master/search-api.md.
You can remove a patient using the command line interface by invoking this command and providing either its ID or its label (or both actually):
pmatcher remove patient [OPTIONS]
Options:
-id TEXT ID of the patient to be removed from database
-label TEXT label of the patient to be removed from database
In order to save patients into patientMatcher you need to create at least one authorized client. Use the following command to insert a client object in the database:
pmatcher add client [OPTIONS]
Options:
-id TEXT Client ID [required]
-token TEXT Authorization token [required]
-url TEXT Client URL [required]
-contact TEXT Client email
POST request aimed at adding or modifying a patient in patientMatcher should be using a token from a client present in the database. Clients may be from the command line with this command:
pmatcher remove client -id client_id
To connect to another MME node and submit requests to it you should know the authentication token to the other node. You can add a node to the database by running the command:
pmatcher add node [OPTIONS]
Options:
-id TEXT Server/Client ID [required]
-token TEXT Authorization token [required]
-matching_url TEXT URL to send match requests to [required]
-accepted_content TEXT Accepted Content-Type [required]
-contact TEXT An email address
Connected nodes may be removed any time using the command:
pmatcher remove node -id node_id
- /patient/add. To add patients using a POST request. Example:
curl -X POST \
-H 'X-Auth-Token: custom_token' \
-H 'Content-Type: application/vnd.ga4gh.matchmaker.v1.0+json' \
-H 'Accept: application/json' \
-d '{"patient":{
"id":"patient_id",
"contact": {"name":"Contact Name", "href":"mailto:[email protected]"},
"features":[{"id":"HP:0009623"}],
"genomicFeatures":[{"gene":{"id":"EFTUD2"}}]
}}' localhost:9020/patient/add
To update the data of a patient already submitted to the server you can use the same command and add a patient with the same ID.
The action of adding or updating a patient in the server will trigger an external search of similar patients from connected nodes. If there are no connected nodes in the database or you are uploading demo data no search will be performed on other nodes.
- patient/delete/<patient_id>. You can delete a patient from the database by sending a DELETE request with its ID to the server. Example:
curl -X DELETE \
-H 'X-Auth-Token: custom_token' \
localhost:9020/patient/delete/patient_id
Please note that when a patient is deleted all its match results will be also deleted from the database. This is valid for matches where the patient was used as the query patient in searches performed on other nodes or the internal patientMatcher database (internal search). Matching results where the removed patient is instead listed among the matching results will be not removed from the database.
- /metrics.
Use this endpoint to get database metrics.
Stats which could be retrieved by a MME service are described here
Example:
curl -X GET \
localhost:9020/metrics
- /nodes. GET the list of connected nodes. Example:
curl -X GET \
-H 'X-Auth-Token: custom_token' \
localhost:9020/nodes
The response will return a list like this : [ { 'id' : node_1_id, 'description' : node1_description }, .. ] or an empty list if the server is not connected to external nodes.
- /match. POST a request with a query patient to patientMatcher and get a response with the patients in the server which are most similar to your query. Example:
curl -X POST \
-H 'X-Auth-Token: custom_token' \
-H 'Content-Type: application/vnd.ga4gh.matchmaker.v1.0+json' \
-H 'Accept: application/vnd.ga4gh.matchmaker.v1.0+json' \
-d '{"patient":{
"id":"patient_id",
"contact": {"name":"Contact Name", "href":"mailto:[email protected]"},
"features":[{"id":"HP:0009623"}],
"genomicFeatures":[{"gene":{"id":"EFTUD2"}}]
}}' localhost:9020/match
The maximum number of patients returned by the server is a parameter which can be customized by editing the "MAX_RESULTS" field in the config.py file. Default value is 5. Patient matches are returned in order or descending similarity with the query patient (The most similar patients are higher in the list of results).
Another customizable parameter is the minimum patient score threshold for returned results (SCORE_THRESHOLD in the config file). Matches with patient score lower than this number won't be returned. Default value for this parameter is 0.
- /match/external/<patient_id>. Trigger a search in external nodes for patients similar to the one specified by the ID. Example:
curl -X POST \
-H 'X-Auth-Token: custom_token' \
localhost:9020/match/external/patient_id
It is possible to search for matching patients on a specific node. To do so specify the node id in the request args. Example:
curl -X POST \
-H 'X-Auth-Token: custom_token' \
localhost:9020/match/external/patient_id?node=specific_node_id
Read here how to get a list with the ID of the connected nodes.
- /matches/<patient_id>. Return all matches (internal and external) with positive results for a patient specified by an ID. Example:
curl -X GET \
-H 'X-Auth-Token: custom_token' \
localhost:9020/matches/patient_id
Each patient query submitted to the server triggers a matching algorithm which will search and return those patients on the server that are most similar to the queried one. Patient similarity is measured by the a similarity score that may span from 0 (no matching) to 1 (exact matching).
Similarity score computation is taking into account genomic similarity and phenotype similarity across patients. The weight of these two factors is numerically evaluated into a GTscore and a PhenoScore, and the sum of the 2 constitutes the similarity score of the matching patient.
The relative weight of the GTscore and the PhenoScore can be customised by the database administrator by changing the values of the parameters "MAX_GT_SCORE" and "MAX_PHENO_SCORE" in the configuration file (instance/config.py). Default values are MAX_GT_SCORE: 0.5, MAX_PHENO_SCORE : 0.5.
GTscore is computed by evaluating the list of genomic features of the queried patient and the patients available on the MME server. PatientMatcher patients are saved with gene ids described by Ensembl gene ids, but it's possible to search the database using patients with genes represented by HGNC symbols, Entrez ids and Ensembl ids.
If the queried patient has no genomic features (only phenotype features) then GTscore of all the returned matches will be 0.
Example of how the algorithm works: Let's assume that 0.5 is the MAX_GT_SCORE possible for a patient match (default parameters).
If for instance the queried patient (QUERY) has 3 variants, each variant will have a relative weight of 0.1666 (0.5/3). 0.1666 will be the maximum score for each variant. Assuming having a QUERY patient with these variants:
- gene X variant A
- gene Y variant B
- gene Z variant C
Any patient in the database having variants in any of the X,Y,Z genes will constitute a match (MATCH) to the queried patient and will be compared against it. Let's assume the variants in MATCH are:
- gene X variant D (1)
- gene Y variant B (2)
- gene W variant E (3)
The evaluation of the matching features is always performed on the QUERY variants, in this way:
- gene X variant A ---> gene match with (1). No variant match. Assigned score: 0.1666/4 (gene match only will be arbitrarily assigned a fourth of the relative weight of the variant)
- gene Y variant B ---> exact matching of variant and gene with (2). Assigned score: 0.1666 (max relative weight of the variant)
- gene Z variant C ---> No match, assigned score: 0.
GTscore assigned to the MATCH patients will then be: 0.1666/4 + 0.1666 + 0.
Note that the algorithm will evaluate and assign a score of 0.1666 (max relative weight of the variant) also to matching variants outside genes. This way patients will be evaluated for genetic similarity even if the variants lay outside genes.
Phenotype similarity is calculated by taking into account features and disorders of a patient.
-
Patient features are specified by the eventual HPO terms provided for the query patient. Similarity between HPO features will be equal the maximum similarity score between two patients if no disorders (OMIM terms) are provided for one or both patients.
Otherwise feature similarity score will make up 1/2 of the maximum similarity score. Feature similarity is calculated as the simgic score obtained by comparing HPO terms of a query patient with those from a matching patient using the patient-similarity software package. You can find more information on semantic similarity comparison algorithms in this paper -
Disorders (OMIM diagnoses), if available, will make up 1/2 of the maximum similarity score. OMIM score is calculated by pairwise comparison of the available OMIM terms for the patients.
Email notification of patient matching can be enabled by editing the email notification parameters in the configuration file (config.py). If you want to test your email configuration without sending real match notifications you could use this command:
pmatcher test email -recipient [email protected]
It is possible to choose to send complete or partial info for matching patients in the email notification body. Set NOTIFY_COMPLETE to True (in config.py) if you want to notify complete patient data (i.e. variants and phenotypes will be shared by email) or set it to False if email body should contain ONLY contact info and patient IDs for all matching patients. This latter option is useful to better secure the access to sensitive data.
Once these parameters are set to valid values a notification email will be sent in the following cases:
- A patient is added to the database and the add request triggers a search on external nodes. There is at least one returned result (/patient/add endpoint).
- An external search is actively performed on connected nodes and returns at least one result (/match/external/<patient_id> endpoint).
- The server is interrogated by an external node and returns at least one match (/match endpoint). In this case a match notification is sent to each contact of the matches (patients in results).
- An internal search is submitted to the server using a patient from the database (/match endpoint) and this search returns at least one match. In this case contact users of all patients involved will be notified (contact from query patient and contacts from the result list of patients).
You can stop server notification any time by commenting the MAIL_SERVER parameter in config file and rebooting the server.