From c6ea16224e8e6e970fdaef2e4b6f30f4fb5f3029 Mon Sep 17 00:00:00 2001 From: Rinke Hoekstra Date: Fri, 19 May 2017 09:16:47 +0200 Subject: [PATCH] Added Docker configuration files and updated readme --- .dockerignore | 1 + Dockerfile.guidelines | 18 ++++ Dockerfile.stardog | 37 +++++++ docker-compose.yml | 21 ++++ entrypoint.sh | 21 ++++ readme.md | 30 +++++- src/app/views.py | 216 +++++++++++++++++++-------------------- src/run.py | 5 +- stardog.properties | 9 ++ start-stardog-service.sh | 30 ++++++ 10 files changed, 273 insertions(+), 115 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile.guidelines create mode 100644 Dockerfile.stardog create mode 100644 docker-compose.yml create mode 100644 entrypoint.sh create mode 100644 stardog.properties create mode 100644 start-stardog-service.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..6b8710a7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.git diff --git a/Dockerfile.guidelines b/Dockerfile.guidelines new file mode 100644 index 00000000..b226e5cb --- /dev/null +++ b/Dockerfile.guidelines @@ -0,0 +1,18 @@ +FROM python:2.7.13-wheezy + +MAINTAINER rinke.hoekstra@vu.nl + +ENV GUIDELINES_APP="/usr/local/guidelines" + +COPY ./requirements.txt /requirements.txt +RUN pip install -r requirements.txt + +COPY ./src ${GUIDELINES_APP} + +COPY entrypoint.sh /sbin/entrypoint.sh +RUN chmod 755 /sbin/entrypoint.sh + +WORKDIR ${GUIDELINES_APP} +ENTRYPOINT ["/sbin/entrypoint.sh"] +CMD ["app:start"] +EXPOSE 5000 diff --git a/Dockerfile.stardog b/Dockerfile.stardog new file mode 100644 index 00000000..c2799bbd --- /dev/null +++ b/Dockerfile.stardog @@ -0,0 +1,37 @@ +FROM java:8-jre-alpine + +ENV STARDOG_VERSION 4.1.2 + +ENV STARDOG_HOME /data +ENV STARDOG_INSTALL_DIR /opt/stardog + +ENV STARDOG_START_PARAMS "" +ENV STARDOG_DB_NAME guidelines +ENV STARDOG_CREATE_PARAMS "-n ${STARDOG_DB_NAME} -v -o versioning.enabled=true preserve.bnode.ids=false strict.parsing=false --" +ENV STARDOG_JAVA_ARGS "-Xms2g -Xmx2g -XX:MaxDirectMemorySize=2g" +ENV PATH ${STARDOG_INSTALL_DIR}/bin:${PATH} + +RUN mkdir -p ${STARDOG_HOME} +RUN mkdir -p ${STARDOG_INSTALL_DIR} + +WORKDIR ${STARDOG_INSTALL_DIR} + +RUN apk update +RUN apk add unzip bash + +ADD stardog-*.zip /tmp +RUN unzip -d /tmp /tmp/stardog-*.zip +RUN rm -f /tmp/stardog-*.zip +RUN cp -r /tmp/stardog-*/* ${STARDOG_INSTALL_DIR}/ +RUN rm -rf /tmp/stardog-* + +ADD stardog-license-key.bin ${STARDOG_INSTALL_DIR} +ADD stardog.properties ${STARDOG_INSTALL_DIR} +ADD start-stardog-service.sh ${STARDOG_INSTALL_DIR} +RUN chmod +x ${STARDOG_INSTALL_DIR}/start-stardog-service.sh + +WORKDIR ${STARDOG_HOME} + +CMD ${STARDOG_INSTALL_DIR}/start-stardog-service.sh + +EXPOSE 5820 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..4ee85c90 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +version: '3' +services: + guidelines: + build: + context: . + dockerfile: Dockerfile.guidelines + ports: + - "127.0.0.1:5000:5000" + environment: + - ENDPOINT_URL=http://stardog:5820/guidelines/query + - UPDATE_URL=http://stardog:5820/guidelines/update + stardog: + build: + context: . + dockerfile: Dockerfile.stardog + environment: + - STARDOG_START_PARAMS=--disable-security + volumes: + - ./src/data/:/var/data + ports: + - "127.0.0.1:5820:5820" diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 00000000..6647a9fc --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -e #exit on errors + +#print statements as they are executed +[[ -n $DEBUG_ENTRYPOINT ]] && set -x + +case ${1} in + app:start) + python run.py + ;; + app:help) + echo "Available options:" + echo " app:start - Starts TMR4i Guidelines Explorer (default)" + echo " [command] - Execute the specified command, eg. /bin/bash." + ;; + *) + exec "$@" + ;; +esac + +exit 0 diff --git a/readme.md b/readme.md index ca2ca66e..eb8f9d50 100644 --- a/readme.md +++ b/readme.md @@ -1,8 +1,29 @@ # Guidelines Demo -This web application can show off the coolness of the TMR and TMR4I ontologies developed by Veruska Zamborlini in detecting interactions between the recommendations of medical guidelines +This web application can show off the coolness of the TMR and TMR4I ontologies developed by Veruska Zamborlini in detecting interactions between the recommendations of medical guidelines. -## Setup +This repository also contains the `metis` application that runs with Swish. You can find a separate readme file in that directory. + +## Setup (using Docker) + +* Make sure you have docker installed on your system () +* Open up a terminal window and clone or download this repository to a location of your choice: + +``` +git clone https://github.com/Data2Semantics/guidelines.git +``` +* Change into the `guidelines` directory +* Download the latest version of Stardog from +* Copy the zipfile for the latest version of Stardog into this directory (e.g. `stardog-5.0-beta.zip`). +* Also copy the `stardog-license-key.bin` file into this directory +* From the command line run `docker-compose build` to create the Docker images + +### Starting (using Docker) + +* Change into the `guidelines` directory and run `docker-compose up` +* Go to `http://localhost:5000` and have fun! + +## Setup (from source) * Make sure you have `pip` and `virtualenv` installed (`easy_install pip`, `pip install virtualenv`) * Go to the directory in which you cloned this Git repository, and install a virtual environment: `virtualenv .` @@ -10,5 +31,8 @@ This web application can show off the coolness of the TMR and TMR4I ontologies d * Install the required packages: `pip install -r requirements.txt` * Make sure you have a properly installed Stardog server running, with **security disabled** (`stardog-admin server start --disable-security`) * Go to the `src` directory, and run `create-stardog.sh` and then `reset-stardog.sh` + +### Starting (from source) + * Inside the `src` directory, run `python run.py` -* Go to `http://localhost:5000` and have fun! \ No newline at end of file +* Go to `http://localhost:5000` and have fun! diff --git a/src/app/views.py b/src/app/views.py index 297c1289..cae6a9f4 100644 --- a/src/app/views.py +++ b/src/app/views.py @@ -1,14 +1,14 @@ -from flask import render_template, g, request, jsonify, make_response -from SPARQLWrapper import SPARQLWrapper +from flask import render_template, request, jsonify import logging import requests import json from app import app import uuid import pprint +import os -ENDPOINT_URL = 'http://localhost:5820/guidelines/query' -UPDATE_URL = 'http://localhost:5820/guidelines/update' +ENDPOINT_URL = os.getenv('ENDPOINT_URL') or 'http://localhost:5820/guidelines/query' +UPDATE_URL = os.getenv('UPDATE_URL') or 'http://localhost:5820/guidelines/update' REASONING_TYPE = 'SL' @@ -20,12 +20,12 @@ 'Accept': 'application/sparql-results+json', 'SD-Connection-String': 'reasoning={}'.format(REASONING_TYPE) } - + UPDATE_HEADERS = { 'Content-Type': 'application/sparql-update', 'SD-Connection-String': 'reasoning={}'.format(REASONING_TYPE) } - + PREFIXES = """ PREFIX tmr4i: PREFIX drugbank: @@ -36,8 +36,8 @@ @app.route("/") def index(): return render_template('base.html') - - + + @app.route('/getinference') def inference(): internal_recommendation_interaction() @@ -46,15 +46,15 @@ def inference(): # Including Alternative Drug External Interactions # The rules for classifying the internal interaction should be already performed - - + + alternative_drugs_external_interaction() - + same_as() - - + + return jsonify({'status': 'Done'}) @@ -62,40 +62,40 @@ def inference(): def guidelines(): print "Retrieving guidelines" query = PREFIXES + "SELECT DISTINCT ?gl ?gl_label WHERE {?rec tmr4i:partOf ?gl . ?gl rdfs:label ?gl_label .}"; - + guidelines = sparql(query, strip=True) return render_template('guidelines_list.html',guidelines = guidelines) - + @app.route('/getrecommendations', methods=['GET']) def recommendations(): print "Retrieving recommendations" guideline_uri = request.args.get('uri', '') guideline_label = request.args.get('label','') - - - + + + query = PREFIXES + """ - SELECT DISTINCT ?rec ?rec_label WHERE - { - ?rec tmr4i:partOf <""" + guideline_uri + """> . + SELECT DISTINCT ?rec ?rec_label WHERE + { + ?rec tmr4i:partOf <""" + guideline_uri + """> . ?rec rdfs:label ?rec_label . ?rec a owl:NamedIndividual . }""" - + recommendations_menu = sparql(query, strip=True) - - + + ## initialize the rest of the results with the stuff for the recommendations menu all_results = [] all_results.extend(recommendations_menu) - + query = PREFIXES + """ - SELECT DISTINCT * WHERE - { - ?rec tmr4i:partOf <""" + guideline_uri + """> . + SELECT DISTINCT * WHERE + { + ?rec tmr4i:partOf <""" + guideline_uri + """> . ?rec rdfs:label ?rec_label . ?rec a owl:NamedIndividual . ?rec tmr4i:interactsInternallyWith ?internal_rec . @@ -180,13 +180,13 @@ def recommendations(): BIND(tmr4i:ExternallyInteractingRecommendation AS ?erec) } """ - + all_results.extend(sparql(query, strip=True)) - + query = PREFIXES + """ - SELECT DISTINCT * WHERE - { - ?rec tmr4i:partOf <""" + guideline_uri + """> . + SELECT DISTINCT * WHERE + { + ?rec tmr4i:partOf <""" + guideline_uri + """> . ?rec rdfs:label ?rec_label . ?rec a owl:NamedIndividual . ?i tmr4i:relates ?rec . @@ -200,9 +200,9 @@ def recommendations(): } """ all_results.extend(sparql(query, strip=True)) - + log.debug(all_results) - + recommendations = [] double_drugs = set() print len(all_results) @@ -210,7 +210,7 @@ def recommendations(): if 'drug1_label' and 'drug2_label' in r: d1 = r['drug1_label']['value'] d2 = r['drug2_label']['value'] - + if (d2,d1) in double_drugs: log.debug("Drug couple already found") else : @@ -218,11 +218,11 @@ def recommendations(): recommendations.append(r) else : recommendations.append(r) - + print len(recommendations) - + pprint.pprint(recommendations) - + return render_template('recommendations_list.html', recommendations_menu = recommendations_menu, recommendations = recommendations, guideline_label = guideline_label) @app.route('/gettransitions', methods=['GET']) @@ -259,8 +259,8 @@ def transitions(): ?srec tmr4i:recommends ?similar_transition . ?srec rdfs:label ?srec_label . } - - + + BIND(IF (bound(?f_condition), ?f_condition, "none") as ?filter_condition) } """ @@ -301,7 +301,7 @@ def transitions(): pos_transitions = sparql(pos_query, strip=True) neg_transitions = sparql(neg_query, strip=True) - + return render_template('transitions_list.html', pos_transitions = pos_transitions, neg_transitions = neg_transitions) @app.route('/getcare_actions', methods=['GET']) @@ -314,27 +314,27 @@ def care_actions(): } """ care_actions = sparql(query, strip=True) - + return render_template('care_actions.html', care_actions = care_actions) - + def sparql_update(query, endpoint_url = UPDATE_URL): - + log.debug(query) - + result = requests.post(endpoint_url,params={'reasoning': REASONING_TYPE}, data=query, headers=UPDATE_HEADERS) - + return result.content def sparql(query, strip=False, endpoint_url = ENDPOINT_URL): """This method replaces the SPARQLWrapper SPARQL interface, since SPARQLWrapper cannot handle the Stardog-style query headers needed for inferencing""" - + result = requests.get(endpoint_url,params={'query': query, 'reasoning': REASONING_TYPE}, headers=QUERY_HEADERS) try : result_dict = json.loads(result.content) except Exception as e: return result.content - + if strip: new_results = [] for r in result_dict['results']['bindings']: @@ -345,37 +345,37 @@ def sparql(query, strip=False, endpoint_url = ENDPOINT_URL): new_result[k+'_label'] = {} new_result[k+'_label']['type'] = 'literal' new_result[k+'_label']['value'] = v['value'][v['value'].rfind('/')+1:] - + elif not k+'_label' in r.keys(): new_result[k+'_label'] = {} new_result[k+'_label']['type'] = 'literal' new_result[k+'_label']['value'] = v['value'] - + new_result[k+'_stripped'] = {} new_result[k+'_stripped']['type'] = 'literal' new_result[k+'_stripped']['value'] = v['value'][v['value'].rfind('/')+1:] - - + + new_result[k] = v - + new_results.append(new_result) - + log.debug(new_results) return new_results else : return result_dict['results']['bindings'] - - - + + + def internal_recommendation_interaction(): query = PREFIXES + """ - SELECT DISTINCT ?r1 ?r2 + SELECT DISTINCT ?r1 ?r2 WHERE - { + { ?r1 a tmr4i:Recommendation . ?r1 a owl:NamedIndividual . ?r2 a tmr4i:Recommendation . @@ -387,8 +387,8 @@ def internal_recommendation_interaction(): ?r2 tmr4i:recommends ?t2 . ?t1 a owl:NamedIndividual . ?t2 a owl:NamedIndividual . - - { + + { ?t1 tmr4i:similarToTransition ?t2 . } UNION @@ -401,7 +401,7 @@ def internal_recommendation_interaction(): ?t2 tmr4i:promotedBy ?ca . } FILTER (?r1 != ?r2 && ?t1 != ?t2) - + # Need to make sure that we are not adding duplicate interactions FILTER NOT EXISTS { ?iir a tmr4i:InternalRecommendationInteraction . @@ -410,23 +410,23 @@ def internal_recommendation_interaction(): } } """ results = sparql(query) - + deduped_results = set() for r in results : one = r['r1']['value'] two = r['r2']['value'] - + if not (two,one) in deduped_results: print "adding", (one,two) deduped_results.add((one,two)) else : - print "result already found", (two,one) - + print "result already found", (two,one) + log.debug("{} interactions found.".format(len(deduped_results))) - + update_template = PREFIXES + """ INSERT DATA - {{ + {{ tmr4i:{0} a tmr4i:InternalRecommendationInteraction, owl:NamedIndividual . tmr4i:{0} tmr4i:relates <{1}> . tmr4i:{0} tmr4i:relates <{2}> . @@ -434,15 +434,15 @@ def internal_recommendation_interaction(): <{2}> tmr4i:interactsInternallyWith <{1}> . }} """ - + for (one,two) in deduped_results : interaction = "internal_recommendation_interaction_{}".format(str(uuid.uuid4())) - + update = update_template.format(interaction, one, two) - + print interaction, one, two result = sparql_update(update) - + results = sparql(query) @@ -454,7 +454,7 @@ def internal_recommendation_interaction(): def incompatible_drugs_external_interaction(): # Including Incompatible Drugs External Interactions query = PREFIXES + """ - + SELECT distinct ?r1 ?r2 ?d1 ?d2 WHERE { ?r1 tmr4i:recommendsToPursue ?t1 . @@ -463,20 +463,20 @@ def incompatible_drugs_external_interaction(): ?t2 tmr4i:promotedBy ?ca2 . ?r1 tmr4i:partOf ?g . ?r2 tmr4i:partOf ?g . - + { ?ca1 tmr4i:involves ?d1 . } UNION { ?ca1 tmr4i:involves ?c1 . ?d1 drugbank:drugCategory ?c1 .} { ?ca2 tmr4i:involves ?d2 . } UNION { ?ca2 tmr4i:involves ?c2 . ?d2 drugbank:drugCategory ?c2 .} ?d1 drugbank:interactsWith ?d2 . - + FILTER(?r1 != ?r2 && ?d1 != ?d2 && ?ca1 != ?ca2 ) - + # Need to make sure that we are not adding duplicate interactions FILTER NOT EXISTS { ?iir a tmr4i:IncompatibleDrugExternalInteraction . ?iir tmr4i:relates ?r1 . ?iir tmr4i:relates ?r2 . } - + } """ results = sparql(query) @@ -487,7 +487,7 @@ def incompatible_drugs_external_interaction(): RTwo = r['r2']['value'] DOne = r['d1']['value'] DTwo = r['d2']['value'] - + if not (RTwo,ROne,DTwo,DOne) in deduped_results: print "adding", (ROne,RTwo,DOne,DTwo) deduped_results.add((ROne,RTwo,DOne,DTwo)) @@ -495,7 +495,7 @@ def incompatible_drugs_external_interaction(): print "result already found", (RTwo,ROne,DTwo,DOne) log.debug("{} external interactions found.".format(len(deduped_results))) - + update_template = PREFIXES + """ INSERT DATA {{ @@ -508,23 +508,23 @@ def incompatible_drugs_external_interaction(): <{2}> tmr4i:interactsExternallyWith <{1}> . }} """ - + for (ROne,RTwo,DOne,DTwo) in deduped_results : interaction = "external_recommendation_interaction_{}".format(str(uuid.uuid4())) - + update = update_template.format(interaction, ROne,RTwo,DOne,DTwo) - + print interaction, ROne,RTwo,DOne,DTwo result = sparql_update(update) - - - - - - - - - + + + + + + + + + def alternative_drugs_external_interaction(): query = PREFIXES + """ SELECT DISTINCT ?rec ?ca ?d ?dALT WHERE @@ -536,14 +536,14 @@ def alternative_drugs_external_interaction(): ?rec tmr4i:recommendsToPursue ?t . ?rec tmr4i:partOf ?g . ?t tmr4i:regards ?dc . #For a transition related with the effect meant by DrugCategory - + ?t tmr4i:promotedBy ?ca . ?ca tmr4i:involves ?d . - + ?dALT drugbank:drugCategory ?dc . #Find alternative drugs with the same effect / Category - + FILTER (?d != ?dALT) . - + FILTER NOT EXISTS #Don't consider alternative drugs that are incompatible with recommended ones { ?dALT drugbank:interactsWith ?d2 . { ?ca2 tmr4i:involves ?d2 . } @@ -553,7 +553,7 @@ def alternative_drugs_external_interaction(): ?rec2 tmr4i:partOf ?g . FILTER(?dALT != ?d2) } - + # Need to make sure that we are not adding duplicate interactions FILTER NOT EXISTS { ?iir a tmr4i:AlternativeDrugExternalInteraction . @@ -562,20 +562,20 @@ def alternative_drugs_external_interaction(): ?iir tmr4i:drug ?d . ?iir tmr4i:alternative_drug ?dALT . } - + } """ - + results = sparql(query) log.debug(results) - + deduped_results = set() for r in results : rec = r['rec']['value'] ca = r['ca']['value'] DOne = r['d']['value'] DTwo = r['dALT']['value'] - + if not (rec,ca,DTwo,DOne) in deduped_results: print "adding", (rec,ca,DOne,DTwo) deduped_results.add((rec,ca,DOne,DTwo)) @@ -583,7 +583,7 @@ def alternative_drugs_external_interaction(): print "result already found", (rec,ca,DTwo,DOne) log.debug("{} external alternative interactions found.".format(len(deduped_results))) - + update_template = PREFIXES + """ INSERT DATA {{ @@ -594,12 +594,12 @@ def alternative_drugs_external_interaction(): tmr4i:{0} tmr4i:alternative_drug <{4}> . }} """ - + for (rec,ca,DOne,DTwo) in deduped_results : interaction = "external_recommendation_interaction_{}".format(str(uuid.uuid4())) - + update = update_template.format(interaction, rec,ca,DOne,DTwo) - + print interaction, rec,ca,DOne,DTwo result = sparql_update(update) @@ -621,7 +621,7 @@ def same_as(): ?i2 a owl:NamedIndividual . { { ?i1 a tmr4i:RepetitionDueToSameAction . ?i2 a tmr4i:RepetitionDueToSameAction .} UNION - { ?i1 a tmr4i:AlternativeDueToSimilarTransition . ?i2 a tmr4i:AlternativeDueToSimilarTransition .} + { ?i1 a tmr4i:AlternativeDueToSimilarTransition . ?i2 a tmr4i:AlternativeDueToSimilarTransition .} } ?g a tmr4i:Guideline, owl:NamedIndividual . ?r1 a tmr4i:Recommendation, owl:NamedIndividual . @@ -637,6 +637,6 @@ def same_as(): FILTER (?r1 != ?r2 && ?r1 != ?r3 && ?r2 != ?r3 && ?i1 != ?i2) } """ - + results = sparql_update(query) - log.debug(results) \ No newline at end of file + log.debug(results) diff --git a/src/run.py b/src/run.py index 7703fa11..bf4d9052 100644 --- a/src/run.py +++ b/src/run.py @@ -1,7 +1,4 @@ from app import app -import webbrowser if __name__ == "__main__": - # webbrowser.open_new_tab('http://localhost:5000') - app.run() - \ No newline at end of file + app.run(host='0.0.0.0') diff --git a/stardog.properties b/stardog.properties new file mode 100644 index 00000000..1cc80c91 --- /dev/null +++ b/stardog.properties @@ -0,0 +1,9 @@ +query.all.graphs = true +database.archetypes=PROV +reasoning.punning.enabled=true +reasoning.type=SL +reasoning.sameas=FULL +search.enabled=true +search.wildcard.search.enabled=true +query.all.graphs=true +strict.parsing=false diff --git a/start-stardog-service.sh b/start-stardog-service.sh new file mode 100644 index 00000000..8d153c08 --- /dev/null +++ b/start-stardog-service.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +rm -f ${STARDOG_HOME}/*.lock +rm -f ${STARDOG_HOME}/*.log + +# copy license from install dir if not already in STARDOG_HOME +if [ ! -f ${STARDOG_HOME}/stardog-license-key.bin ]; then + cp ${STARDOG_INSTALL_DIR}/stardog-license-key.bin ${STARDOG_HOME}/stardog-license-key.bin +fi + +# copy server properties from install dir if not already in STARDOG_HOME +if [ ! -f ${STARDOG_HOME}/stardog.properties ]; then + cp ${STARDOG_INSTALL_DIR}/stardog.properties ${STARDOG_HOME}/stardog.properties +fi + +echo "starting stardog with the following environment:" +echo "STARDOG_START_PARAMS: ${STARDOG_START_PARAMS}" +echo "STARDOG_CREATE_PARAMS: ${STARDOG_CREATE_PARAMS}" +echo "STARDOG_DB_NAME: ${STARDOG_DB_NAME}" + +${STARDOG_INSTALL_DIR}/bin/stardog-admin server start ${STARDOG_START_PARAMS} +${STARDOG_INSTALL_DIR}/bin/stardog-admin db create ${STARDOG_CREATE_PARAMS} +${STARDOG_INSTALL_DIR}/bin/stardog data add ${STARDOG_DB_NAME} /var/data/*.nq +${STARDOG_INSTALL_DIR}/bin/stardog data add ${STARDOG_DB_NAME} /var/data/*.ttl +${STARDOG_INSTALL_DIR}/bin/stardog data add ${STARDOG_DB_NAME} /var/data/*.rdf +${STARDOG_INSTALL_DIR}/bin/stardog data add ${STARDOG_DB_NAME} /var/data/*.trig +${STARDOG_INSTALL_DIR}/bin/stardog data add ${STARDOG_DB_NAME} /var/data/*.nt + +${STARDOG_INSTALL_DIR}/bin/stardog-admin server stop +${STARDOG_INSTALL_DIR}/bin/stardog-admin server start --foreground --disable-security ${STARDOG_START_PARAMS}