diff --git a/api/graph.py b/api/graph.py new file mode 100644 index 0000000000000000000000000000000000000000..965dd845c1c1e7db0f3c718fce6c178966992b32 --- /dev/null +++ b/api/graph.py @@ -0,0 +1,158 @@ +from neo4j import GraphDatabase +import time + +URL = 'jdbc:postgresql://db/discussion?user=postgres&password=FooBar' + + +class Graph(object): + def __init__(self, uri, user, password): + self._driver = GraphDatabase.driver(uri, auth=(user, password)) + + def close(self): + self._driver.close() + + def load(self): + t0 = self.run(self._delete_everything) + t1 = self.run(self._create_index_on_statement_uid) + t2 = self.run(self._create_statement_nodes) + t3 = self.run(self._fill_statements_with_content) + t4 = self.run(self._create_user_nodes) + t5 = self.run(self._create_relations_between_users_and_statements) + t6 = self.run(self._create_issue_nodes) + t7 = self.run(self._connect_issues_with_statements) + t8 = self.run(self._every_user_likes_his_position) + t9 = self.run(self._create_random_ratings) + t10 = self.run(self._delete_zero_ratings) + + return { + "delete_time": t0, + "index_time": t1, + "statement_node_time": t2, + "statement_content_time": t3, + "user_node_time": t4, + "statement_user_relation_time": t5, + "issue_node_time": t6, + "statement_to_issue_time": t7, + "user_rates_own_positions_time": t8, + "random_ratings_time": t9, + "delete_zero_ratings_time": t10 + } + + def run(self, func): + t1 = time.time() + with self._driver.session() as session: + session.write_transaction(func) + return time.time() - t1 + + @staticmethod + def _create_index_on_statement_uid(tx): + result = tx.run( + "CREATE INDEX ON :Statement(uid) " + ) + return result + + @staticmethod + def _create_index_on_user_uid(tx): + result = tx.run( + "CREATE INDEX ON :Statement(uid) " + ) + return result + + @staticmethod + def _create_statement_nodes(tx): + result = tx.run( + "CALL apoc.load.jdbc($url, 'statements') " + "YIELD row " + "MERGE (statement:Statement{uid:row.uid, is_position:row.is_position, is_disabled:row.is_disabled})" + , url=URL + ) + return result + + @staticmethod + def _fill_statements_with_content(tx): + result = tx.run( + "CALL apoc.load.jdbc($url, 'textversions') " + "YIELD row " + "MATCH (statement:Statement{uid:row.statement_uid}) " + "WHERE NOT EXISTS(statement.content) " + "SET statement += {content:row.content}" + , url=URL + ) + return result + + @staticmethod + def _create_user_nodes(tx): + result = tx.run( + "CALL apoc.load.jdbc($url, 'users') " + "YIELD row " + "MERGE (user:User{uid:row.uid, public_nickname:row.public_nickname})" + , url=URL + ) + return result + + @staticmethod + def _create_relations_between_users_and_statements(tx): + result = tx.run( + "CALL apoc.load.jdbc($url, 'textversions') " + "YIELD row " + "MATCH (user:User), (statement:Statement) " + "WHERE user.uid = row.author_uid AND statement.uid = row.statement_uid " + "MERGE (user)-[:HAS_WRITTEN]->(statement)" + , url=URL + ) + return result + + @staticmethod + def _create_issue_nodes(tx): + result = tx.run( + "CALL apoc.load.jdbc($url, 'issues') " + "YIELD row " + "MERGE (issue:Issue{uid:row.uid, title:row.title})" + , url=URL + ) + return result + + @staticmethod + def _connect_issues_with_statements(tx): + result = tx.run( + "CALL apoc.load.jdbc($url, 'statement_to_issue') " + "YIELD row " + "MATCH (statement:Statement{uid:row.statement_uid}), (issue:Issue{uid:row.issue_uid}) " + "MERGE (statement)-[:WRITTEN_IN]->(issue)" + , url=URL + ) + return result + + @staticmethod + def _every_user_likes_his_position(tx): + result = tx.run( + "MATCH(user:User)-[:HAS_WRITTEN]->(statement:Statement{is_position:True}) " + "MERGE(user)-[:LIKES{rating: 5}]->(statement)" + ) + return result + + @staticmethod + def _create_random_ratings(tx): + result = tx.run( + "MATCH (user:User) " + "WHERE NOT EXISTS((user)-[:LIKES]->()) " + "MATCH (statement:Statement{is_position: True}) " + "MERGE (user)-[:LIKES{rating:round(rand()*5)}]->(statement)" + ) + return result + + @staticmethod + def _delete_zero_ratings(tx): + result = tx.run( + "MATCH ()-[r:LIKES{rating:0.0}]->() " + "DETACH DELETE r" + ) + return result + + @staticmethod + def _delete_everything(tx): + result = tx.run( + "MATCH (a) " + "DETACH DELETE a" + ) + return result diff --git a/api/requirements.txt b/api/requirements.txt index 21ecabbfe476ecce35af9e20dfe006fed2bd116a..5c69b29e609207171ec4c881a7ebcff838ecd240 100644 --- a/api/requirements.txt +++ b/api/requirements.txt @@ -1,2 +1,3 @@ Flask==0.10.1 -flask-cors==3.0.7 \ No newline at end of file +flask-cors==3.0.7 +neo4j==1.7.1 \ No newline at end of file diff --git a/api/server.py b/api/server.py index b2bf2c7414cb0ed065ec85a663644d4c8c7150fb..6d5ede2433851d573d6e0b28074939638aacfa2b 100644 --- a/api/server.py +++ b/api/server.py @@ -1,6 +1,8 @@ -from flask import Flask, render_template +from flask import Flask, render_template, jsonify from flask_cors import CORS +from api.graph import Graph + app = Flask(__name__, template_folder='.') CORS(app) @@ -10,5 +12,10 @@ def root(file): return render_template('html/' + file) +@app.route('/load') +def test(): + return jsonify(Graph(uri='bolt://neo:7687', user='neo4j', password='neo4j').load()) + + if __name__ == '__main__': app.run(debug=True, host="0.0.0.0", port=5000)