From b8bb041d27f61f69e287c96b3575e110a1ccfe44 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Mar 2021 08:38:53 +0100 Subject: [PATCH 1/9] chore: ignore vim files. --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2a25f74..f50a1ba 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ oracle-of-bacon-backend/.data/ node_modules imdb-data - +*.swp +*.class From a2ac3edb259e963e38d6c96c278a273da845ee91 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Mar 2021 13:49:55 +0100 Subject: [PATCH 2/9] docs: add instructions to load dataset --- oracle-of-bacon-backend/instructions-neo4j.md | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 oracle-of-bacon-backend/instructions-neo4j.md diff --git a/oracle-of-bacon-backend/instructions-neo4j.md b/oracle-of-bacon-backend/instructions-neo4j.md new file mode 100644 index 0000000..1fdb16c --- /dev/null +++ b/oracle-of-bacon-backend/instructions-neo4j.md @@ -0,0 +1,115 @@ +This is the instruction to replicate the results over neo4j bacon + +1 - create a connection dbms to neo4j + User: oracle-bacon + Password: password +2 - import the data + In the folder of imports copy the three files + ***actors.csv, movies.csv, roles.csv*** +3 - in your terminal execute bin/cyphershell + User: neo4j + password: password # this is the password of your dbms +4 - Run the following commands in cyphershell +4.1 - First check that the data is right executing the following commands +These commands will return the number of lines, (you should see something like this) + + +``` +neo4j@neo4j> LOAD CSV FROM 'file:///actors.csv' AS row RETURN count(row); ++------------+ +| count(row) | ++------------+ +| 1854871 | ++------------+ + +neo4j@neo4j> LOAD CSV FROM 'file:///movies.csv' AS row RETURN count(row); ++------------+ +| count(row) | ++------------+ +| 759282 | ++------------+ + +neo4j@neo4j> LOAD CSV FROM 'file:///roles.csv' AS row RETURN count(row); ++------------+ +| count(row) | ++------------+ +| 13103223 | ++------------+ + + +``` + + +5- Now let's load the data, the following lines ensure that even if you +execute the same script, will not repeat information :v + + +Actors +``` +:auto USING PERIODIC COMMIT +LOAD CSV WITH HEADERS FROM 'file:///actors.csv' AS line +WITH line.`name:ID` as name +MERGE(o:Actor{name:name}) set o.name=name +RETURN count(o); +``` + +Movies +``` +:auto USING PERIODIC COMMIT +LOAD CSV WITH HEADERS FROM 'file:///movies.csv' AS line +WITH line.`title:ID` as title +MERGE(o:Movie{title:title}) set o.title=title +RETURN count(o); +``` + +Relations +``` +:auto USING PERIODIC COMMIT 500 +LOAD CSV WITH HEADERS FROM 'file:///roles.csv' +AS line WITH line.`:END_ID` as title, line.`:TYPE` +as relation, line.`:START_ID` as actor +MATCH (a:Actor{name:actor}) +MATCH (m:Movie{title:title}) +MERGE (a)-[rel:PLAYED_IN]->(m) +RETURN count(rel); +``` + + +Queries + +Get some actors and movies where they played in +``` +MATCH (o:Actor)-[rel:PLAYED_IN]->(p:Movie) RETURN p,rel,o LIMIT 50; +``` + +Delete all connection type ```relation``` +``` +match(n)-[r:relation]-(o) delete r; +``` + +Get movies of a given actor +``` +match p=(n:Actor)-[r:PLAYED_IN]-(o:Movie) where n.name="Bacon, Kevin (I)" return p; +match p=(n:Actor)-[r:PLAYED_IN]-(o:Movie) where n.name="A., Randy" return p; + +``` + +Get subgraphs +``` +MATCH (o:Actor)-[rel:PLAYED_IN]->(p:Movie) +RETURN p,rel,o LIMIT 100; +``` + + +Get all nodes related to a given node(in this case nodes related to Abadie, William + +``` +match p=(n:Actor)-[*]-(o:Movie) where n.name="Abadie, William" return p; +``` + + +With the last query now it rests to implement it in java, here we have the link + +(Neo4j Data)[https://neo4j.com/developer/java/) + +For further information please visit [Import Data](https://neo4j.com/developer/desktop-csv-import/) From 23945e5711b25af5df33be063d16386f34a90d0d Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Mar 2021 13:53:00 +0100 Subject: [PATCH 3/9] feat(neo4j): fetch data from neo4jdb --- .../oracle/of/bacon/api/APIEndPoint.java | 41 +----------- .../of/bacon/repository/Neo4JRepository.java | 65 ++++++++++++++++--- 2 files changed, 58 insertions(+), 48 deletions(-) diff --git a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java index c2a35df..194a109 100644 --- a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java +++ b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java @@ -22,47 +22,8 @@ public APIEndPoint() { } @Get("bacon-to?actor=:actorName") - // TODO change return type public String getConnectionsToKevinBacon(String actorName) { - return "[\n" + - "{\n" + - "\"data\": {\n" + - "\"id\": 85449,\n" + - "\"type\": \"Actor\",\n" + - "\"value\": \"Bacon, Kevin (I)\"\n" + - "}\n" + - "},\n" + - "{\n" + - "\"data\": {\n" + - "\"id\": 2278636,\n" + - "\"type\": \"Movie\",\n" + - "\"value\": \"Mystic River (2003)\"\n" + - "}\n" + - "},\n" + - "{\n" + - "\"data\": {\n" + - "\"id\": 1394181,\n" + - "\"type\": \"Actor\",\n" + - "\"value\": \"Robbins, Tim (I)\"\n" + - "}\n" + - "},\n" + - "{\n" + - "\"data\": {\n" + - "\"id\": 579848,\n" + - "\"source\": 85449,\n" + - "\"target\": 2278636,\n" + - "\"value\": \"PLAYED_IN\"\n" + - "}\n" + - "},\n" + - "{\n" + - "\"data\": {\n" + - "\"id\": 9985692,\n" + - "\"source\": 1394181,\n" + - "\"target\": 2278636,\n" + - "\"value\": \"PLAYED_IN\"\n" + - "}\n" + - "}\n" + - "]"; + return neo4JRepository.connectionsToJson(neo4JRepository.getConnections(actorName)); } @Get("suggest?q=:searchQuery") diff --git a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/Neo4JRepository.java b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/Neo4JRepository.java index e5490f4..3c847b7 100644 --- a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/Neo4JRepository.java +++ b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/Neo4JRepository.java @@ -1,15 +1,16 @@ package com.serli.oracle.of.bacon.repository; +import java.util.ArrayList; import java.util.List; import java.util.Map; -import org.neo4j.driver.AuthTokens; -import org.neo4j.driver.Driver; -import org.neo4j.driver.GraphDatabase; -import org.neo4j.driver.Session; +import org.neo4j.driver.*; import org.neo4j.driver.types.Node; +import org.neo4j.driver.types.Path; import org.neo4j.driver.types.Relationship; +import static org.neo4j.driver.Values.parameters; + public class Neo4JRepository { private final Driver driver; @@ -17,11 +18,36 @@ public Neo4JRepository() { this.driver = GraphDatabase.driver("bolt://localhost:7687", AuthTokens.basic("neo4j", "password")); } - public List> getConnectionsToKevinBacon(String actorName) { - Session session = driver.session(); + public List getConnections(String actorName) { + List res = new ArrayList<>(); + + try (Session session = driver.session()) { + String query = "match p=(n:Actor)-[*]-(o:Movie) where n.name=$actorName return p"; + Result result = session.run(query, parameters("actorName", actorName)); + while (result.hasNext()) { + Record x = result.next(); + Path p = x.get(0).asPath(); + for (Node n : p.nodes()) { + GraphNode darkVaderNode = mapNodeToGrapNode(n); + res.add(darkVaderNode); + } + for (Relationship r : p.relationships()) { + GraphEdge darkVaderRel = mapRelationShipToNodeEdge(r); + res.add(darkVaderRel); + } + } + } + return res; + } - // TODO - return null; + public String connectionsToJson(List res) { + String json = "["; + for (int i = 0; i < res.size(); i++) { + if (i != 0) json += ","; + json += res.get(i).toString(); + } + json += "]"; + return json; } private GraphEdge mapRelationShipToNodeEdge(Relationship relationship) { @@ -72,6 +98,17 @@ public GraphNode(long id, String value, String type) { this.value = value; this.type = type; } + + @Override + public String toString() { + return "{\n" + + "\"data\": {\n" + + "\"id\":" + id + ",\n" + + "\"type\": \"" + type + "\",\n" + + "\"value\": \"" + value + "\"\n" + + "}\n" + + "}\n"; + } } private static class GraphEdge extends GraphItem { @@ -85,5 +122,17 @@ public GraphEdge(long id, long source, long target, String value) { this.target = target; this.value = value; } + + @Override + public String toString() { + return "{\n" + + "\"data\": {\n" + + "\"id\": " + id + ",\n" + + "\"source\": " + source + ",\n" + + "\"target\": " + target + ",\n" + + "\"value\": \"" + value + "\"\n" + + "}\n" + + "}\n"; + } } } From 878c67413a9595100dc2c56f2d7b1e3d3dec1527 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Mar 2021 14:39:09 +0100 Subject: [PATCH 4/9] feat(redis): implement get last n search --- .../com/serli/oracle/of/bacon/api/APIEndPoint.java | 7 ++----- .../oracle/of/bacon/repository/RedisRepository.java | 13 ++++++++++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java index 194a109..77db523 100644 --- a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java +++ b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java @@ -23,6 +23,7 @@ public APIEndPoint() { @Get("bacon-to?actor=:actorName") public String getConnectionsToKevinBacon(String actorName) { + redisRepository.insertSearch(actorName); return neo4JRepository.connectionsToJson(neo4JRepository.getConnections(actorName)); } @@ -37,10 +38,6 @@ public List getActorSuggestion(String searchQuery) throws IOException { @Get("last-searches") public List last10Searches() { - return Arrays.asList("Peckinpah, Sam", - "Robbins, Tim (I)", - "Freeman, Morgan (I)", - "De Niro, Robert", - "Pacino, Al (I)"); + return redisRepository.getLastNSearches(10); } } diff --git a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/RedisRepository.java b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/RedisRepository.java index 38f86c9..f3f4602 100644 --- a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/RedisRepository.java +++ b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/RedisRepository.java @@ -1,5 +1,7 @@ package com.serli.oracle.of.bacon.repository; +import java.sql.Timestamp; +import java.util.Date; import java.util.List; import redis.clients.jedis.Jedis; @@ -11,8 +13,13 @@ public RedisRepository() { this.jedis = new Jedis("localhost"); } - public List getLastTenSearches() { - // TODO - return null; + public void insertSearch(String search){ + // insert in a sorted set (timestamp: search) + Timestamp ts = new Timestamp(new Date().getTime()); + jedis.zadd("search", ts.getTime(), search); + } + + public List getLastNSearches( int n ) { + return (List) jedis.zrange("search",0, n); } } From cfac1e3a9aadc74e5e474186bdd7c0e31247c097 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Mar 2021 15:30:15 +0100 Subject: [PATCH 5/9] feat(elastic): implement suggestions with elastic search --- .../oracle/of/bacon/api/APIEndPoint.java | 8 +--- .../repository/ElasticSearchRepository.java | 45 ++++++++++++++++--- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java index 77db523..d2c0fd5 100644 --- a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java +++ b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java @@ -28,12 +28,8 @@ public String getConnectionsToKevinBacon(String actorName) { } @Get("suggest?q=:searchQuery") - public List getActorSuggestion(String searchQuery) throws IOException { - return Arrays.asList("Niro, Chel", - "Senanayake, Niro", - "Niro, Juan Carlos", - "de la Rua, Niro", - "Niro, Simão"); + public List getActorSuggestion(String searchQuery) throws Exception { + return elasticSearchRepository.getActorsSuggests(searchQuery); } @Get("last-searches") diff --git a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/ElasticSearchRepository.java b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/ElasticSearchRepository.java index 045c7a7..ec333a7 100644 --- a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/ElasticSearchRepository.java +++ b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/ElasticSearchRepository.java @@ -1,11 +1,18 @@ package com.serli.oracle.of.bacon.repository; -import java.io.IOException; +import java.util.ArrayList; import java.util.List; - import org.apache.http.HttpHost; +import org.elasticsearch.action.admin.indices.get.GetIndexRequest; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.builder.SearchSourceBuilder; + public class ElasticSearchRepository { @@ -13,7 +20,6 @@ public class ElasticSearchRepository { public ElasticSearchRepository() { client = createClient(); - } public static RestHighLevelClient createClient() { @@ -24,8 +30,35 @@ public static RestHighLevelClient createClient() { ); } - public List getActorsSuggests(String searchQuery) throws IOException { - // TODO - return null; + public boolean indexExist(String index) throws Exception { + GetIndexRequest request = new GetIndexRequest(); + request.indices(index); + return this.client.indices().exists(request, RequestOptions.DEFAULT); + } + + + private SearchRequest createSearchRequest(String searchQuery, String index) throws Exception { + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + searchSourceBuilder + .query(QueryBuilders.multiMatchQuery(searchQuery, "name", "title")); //looking in authors and movies + if (!this.indexExist(index) ){ + throw new Exception("E01: Index not found" + index); + } + return new SearchRequest(index).source(searchSourceBuilder); + } + + public List getActorsSuggests(String searchQuery) throws Exception { + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + searchSourceBuilder + .query(QueryBuilders.multiMatchQuery(searchQuery, "name", "title")); + SearchResponse response = client.search(createSearchRequest(searchQuery, "suggestions"), RequestOptions.DEFAULT); + ArrayList ans = new ArrayList<>(); + if (response.getHits().getTotalHits().value == 0){ + return ans; + } + for (SearchHit hit : response.getHits().getHits()) { + ans.add(hit.getSourceAsString()); + } + return ans; } } From b5b9fd8298ad235085ba99ea37b893aabcfb20ba Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Mar 2021 17:57:32 +0100 Subject: [PATCH 6/9] style(nodes): enhance look & feel. --- oracle-of-bacon-frontend/index.html | 2 ++ oracle-of-bacon-frontend/package-lock.json | 1 + oracle-of-bacon-frontend/package.json | 2 +- oracle-of-bacon-frontend/src/App.vue | 10 +++++--- .../src/components/ActorSearch.vue | 9 +++++-- .../src/components/SearchResult.vue | 24 +++++++++++++++---- oracle-of-bacon-frontend/vite.config.ts | 2 +- 7 files changed, 38 insertions(+), 12 deletions(-) diff --git a/oracle-of-bacon-frontend/index.html b/oracle-of-bacon-frontend/index.html index 11603f8..edca92d 100644 --- a/oracle-of-bacon-frontend/index.html +++ b/oracle-of-bacon-frontend/index.html @@ -4,6 +4,8 @@ + + Vite App diff --git a/oracle-of-bacon-frontend/package-lock.json b/oracle-of-bacon-frontend/package-lock.json index b75aea5..6c25e04 100644 --- a/oracle-of-bacon-frontend/package-lock.json +++ b/oracle-of-bacon-frontend/package-lock.json @@ -5,6 +5,7 @@ "requires": true, "packages": { "": { + "name": "frontend", "version": "0.0.0", "dependencies": { "cytoscape": "^3.18.1", diff --git a/oracle-of-bacon-frontend/package.json b/oracle-of-bacon-frontend/package.json index a073ce6..dda3212 100644 --- a/oracle-of-bacon-frontend/package.json +++ b/oracle-of-bacon-frontend/package.json @@ -18,7 +18,7 @@ }, "proxy": { "/api": { - "target": "https://localhost:8000" + "target": "https://localhost:8001" } } } diff --git a/oracle-of-bacon-frontend/src/App.vue b/oracle-of-bacon-frontend/src/App.vue index 507b8d9..f9a979e 100644 --- a/oracle-of-bacon-frontend/src/App.vue +++ b/oracle-of-bacon-frontend/src/App.vue @@ -3,8 +3,8 @@ - - + + @@ -20,6 +20,7 @@ export default defineComponent({ data() { return { actorName: "", + getSome:"", }; }, components: { @@ -31,6 +32,9 @@ export default defineComponent({ consultOracle(actorName: string) { this.actorName = actorName; }, + getOracle(actorName: string) { + this.getSome = this.getSome + 'a'; + }, }, }); @@ -66,7 +70,7 @@ h1 { } .menu { - background-color: #5a847e; + background-color: #317347; color: #fbffc3; position: absolute; width: 100%; diff --git a/oracle-of-bacon-frontend/src/components/ActorSearch.vue b/oracle-of-bacon-frontend/src/components/ActorSearch.vue index a93e62d..fb0dc4f 100644 --- a/oracle-of-bacon-frontend/src/components/ActorSearch.vue +++ b/oracle-of-bacon-frontend/src/components/ActorSearch.vue @@ -3,12 +3,13 @@
- + +
response.json()) diff --git a/oracle-of-bacon-frontend/src/components/SearchResult.vue b/oracle-of-bacon-frontend/src/components/SearchResult.vue index e2a5a04..dcfa1cb 100644 --- a/oracle-of-bacon-frontend/src/components/SearchResult.vue +++ b/oracle-of-bacon-frontend/src/components/SearchResult.vue @@ -22,9 +22,9 @@ const drawChart = ( .style({ "background-color": (node: any) => { if (node.data("type") === "Movie") { - return "#617d57"; + return "#2196f3"; } else if (node.data("type") === "Actor") { - return "#30514c"; + return "#00be76"; } return "black"; }, @@ -50,14 +50,14 @@ const drawChart = ( "text-halign": "center", "text-outline-color": (node: any) => { if (node.data("type") === "Movie") { - return "#617d57"; + return "#2196f3"; } else if (node.data("type") === "Actor") { - return "#30514c"; + return "#00be76"; } return "black"; }, "text-outline-width": 10, - color: "white", + color: "black", "text-wrap": "wrap", label: "data(value)", }) @@ -75,6 +75,7 @@ export default defineComponent({ name: "search-result", props: { actorName: String, + getSome: String, }, watch: { actorName(newName) { @@ -90,6 +91,19 @@ export default defineComponent({ (this.$refs.cytos as HTMLDivElement).style.visibility = "hidden"; } }, + getSome(newName) { + console.log("get some", newName); + if (newName) { + (this.$refs.cytos as HTMLDivElement).style.visibility = "visible"; + fetch(`/api/some-nodes`) + .then((response) => response.json()) + .then((bodyJson) => { + drawChart(this.$refs.cytos as HTMLDivElement, bodyJson, newName); + }); + } else { + (this.$refs.cytos as HTMLDivElement).style.visibility = "hidden"; + } + }, }, }); diff --git a/oracle-of-bacon-frontend/vite.config.ts b/oracle-of-bacon-frontend/vite.config.ts index 5f1332c..f340c0d 100644 --- a/oracle-of-bacon-frontend/vite.config.ts +++ b/oracle-of-bacon-frontend/vite.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ server: { proxy: { "/api": { - target: "http://localhost:8000", + target: "http://localhost:8001", changeOrigin: true, secure: false, rewrite: (path) => path.replace(/^\/api/, ""), From fa150b8e0aec2de703e2596c1d562783256e7428 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Mar 2021 17:59:35 +0100 Subject: [PATCH 7/9] feat: implement api method to get random nodes. --- .../oracle/of/bacon/api/APIEndPoint.java | 5 ++++ .../of/bacon/repository/Neo4JRepository.java | 23 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java index d2c0fd5..3cd4223 100644 --- a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java +++ b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/api/APIEndPoint.java @@ -27,6 +27,11 @@ public String getConnectionsToKevinBacon(String actorName) { return neo4JRepository.connectionsToJson(neo4JRepository.getConnections(actorName)); } + @Get("some-nodes") + public String getSomeNodes(String actorName) { + return neo4JRepository.connectionsToJson(neo4JRepository.getSomeNodes()); + } + @Get("suggest?q=:searchQuery") public List getActorSuggestion(String searchQuery) throws Exception { return elasticSearchRepository.getActorsSuggests(searchQuery); diff --git a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/Neo4JRepository.java b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/Neo4JRepository.java index 3c847b7..9ac599d 100644 --- a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/Neo4JRepository.java +++ b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/Neo4JRepository.java @@ -40,6 +40,28 @@ public List getConnections(String actorName) { return res; } + public List getSomeNodes() { + List res = new ArrayList<>(); + + try (Session session = driver.session()) { + String query = "match p=(n:Actor)-[*]-(o:Movie) return p limit 5"; //query testing + Result result = session.run(query, parameters("actorName", "")); + while (result.hasNext()) { + Record x = result.next(); + Path p = x.get(0).asPath(); + for (Node n : p.nodes()) { + GraphNode darkVaderNode = mapNodeToGrapNode(n); + res.add(darkVaderNode); + } + for (Relationship r : p.relationships()) { + GraphEdge darkVaderRel = mapRelationShipToNodeEdge(r); + res.add(darkVaderRel); + } + } + } + return res; + } + public String connectionsToJson(List res) { String json = "["; for (int i = 0; i < res.size(); i++) { @@ -47,6 +69,7 @@ public String connectionsToJson(List res) { json += res.get(i).toString(); } json += "]"; + Utils.print("json-neo4j", json); return json; } From c42538d8ee8437d2e609c863f69de341396ed85f Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Mar 2021 18:02:24 +0100 Subject: [PATCH 8/9] docs(readme): add main documentation. --- README.md | 66 ++++++++++++-------------------------------------- last.md | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++ result.png | Bin 0 -> 84032 bytes 3 files changed, 85 insertions(+), 51 deletions(-) create mode 100644 last.md create mode 100644 result.png diff --git a/README.md b/README.md index d69ceb6..b293707 100644 --- a/README.md +++ b/README.md @@ -1,70 +1,34 @@ -# Oracle of Bacon -## Présentation +### Oracle Bacon +Some project which uses +- Elastic search +- Neo4j +- Redis -L'objectif de l'application est de déterminer le degré de séparation entre Kevin Bacon et un acteur donné via ses rôles dans les films. +![](./result.png) -Par exemple : **Al Pacino** -- **Al Pacino** a joué dans `Carlito’s Way` avec `Nelson Vasquez` -- `Nelson Vasquez` a joué dans `The Guiding Light` avec **Kevin Bacon** +#### Instructions -![](./example-oracle-of-bacon.png) -## Les modules - -Le projet est réparti en deux modules : - -- [Le back end](./oracle-of-bacon-backend) qui gère la logique et la connexion aux différents Data Stores. -- [Le front end](./oracle-of-bacon-frontend) qui expose l'IHM. - -## Pour démarrer - -Pour lancer le projet démarrez deux terminaux et positionnez-vous dans ce répertoire : - -```BASH -cd -``` - -Dans le premier, lancez le frontend : - -```BASH +```sh cd oracle-of-bacon-frontend npm install npm run dev ``` -Dans le second, lancez le backend : - -```BASH +```sh cd oracle-of-bacon-backend ./gradlew run ``` -Rendez-vous sur a page http://localhost:8080. - -Pour la suite du projet, nous vous conseillons d'importer le backend dans votre IDE/éditeur préféré. Sauf désir de créativité :smiley:, vous n'avez rien à faire dans le front-end. - -## Le data set - -Les données sont des données qui proviennent de imdb, le dataset est disponible ici : http://bit.ly/imdbdataset - -## Votre mission - -Le site a été bouchonné (cf `TODO`), vous devez effectuer les tâches suivantes : - -- Importer les données dans Neo4J à l'aide de l'outil d'import : [`ìmport-tool`](http://neo4j.com/docs/operations-manual/current/tutorial/import-tool/). -- Implémenter l'Oracle de Bacon à l'aide de Neo4J dans la méthode `com.serli.oracle.of.bacon.repository.Neo4JRepository#getConnectionsToKevinBacon` -- Implémenter la gestion du last 10 search à l'aide de Redis dans la méthode `com.serli.oracle.of.bacon.repository.RedisRepository#getLastTenSearches` -- Importer les données à l'aide de ElasticSearch dans `com.serli.oracle.of.bacon.loader.elasticsearch.CompletionLoader` (alternativement vous pouvez importer les données avec le script node dans `script/insert.js`) (les liens suivants pourront vous aider : [search](https://www.elastic.co/guide/en/elasticsearch/reference/current/search.html), [mapping](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html) et [suggest](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters.html)) -- Implémenter la suggestion sur le nom des acteurs dans `com.serli.oracle.of.bacon.repository.ElasticSearchRepository#getActorsSuggests` +#### Configurations -L'évaluation de votre travail sera effectuée selon les critères suivants : +- To load the datasets in neo4j peruse the document oracle-of-bacon-backend/instructions-neo4j.md +- Load the data in elastic search with index name suggestions +- Start ( Redis, Neo4j, Elastic Search) -- Bon fonctionnement (First make it work) -- Qualité de la solution implémentée (Then make it good) -- Qualité générale de votre code (et de vos commits, il ne faut pas pousser :smiley:) -La livraison de votre travail s'effectue à l'aide d'une pull-request sur le repository https://github.com/nosql-bootcamp/oracle-of-bacon. -**Vous devez commencer par forker le repository https://github.com/nosql-bootcamp/oracle-of-bacon** +#### Authors +- Guillem Sanyas and Daniel Santos diff --git a/last.md b/last.md new file mode 100644 index 0000000..d69ceb6 --- /dev/null +++ b/last.md @@ -0,0 +1,70 @@ +# Oracle of Bacon + +## Présentation + +L'objectif de l'application est de déterminer le degré de séparation entre Kevin Bacon et un acteur donné via ses rôles dans les films. + +Par exemple : **Al Pacino** + +- **Al Pacino** a joué dans `Carlito’s Way` avec `Nelson Vasquez` +- `Nelson Vasquez` a joué dans `The Guiding Light` avec **Kevin Bacon** + +![](./example-oracle-of-bacon.png) + +## Les modules + +Le projet est réparti en deux modules : + +- [Le back end](./oracle-of-bacon-backend) qui gère la logique et la connexion aux différents Data Stores. +- [Le front end](./oracle-of-bacon-frontend) qui expose l'IHM. + +## Pour démarrer + +Pour lancer le projet démarrez deux terminaux et positionnez-vous dans ce répertoire : + +```BASH +cd +``` + +Dans le premier, lancez le frontend : + +```BASH +cd oracle-of-bacon-frontend +npm install +npm run dev +``` + +Dans le second, lancez le backend : + +```BASH +cd oracle-of-bacon-backend +./gradlew run +``` + +Rendez-vous sur a page http://localhost:8080. + +Pour la suite du projet, nous vous conseillons d'importer le backend dans votre IDE/éditeur préféré. Sauf désir de créativité :smiley:, vous n'avez rien à faire dans le front-end. + +## Le data set + +Les données sont des données qui proviennent de imdb, le dataset est disponible ici : http://bit.ly/imdbdataset + +## Votre mission + +Le site a été bouchonné (cf `TODO`), vous devez effectuer les tâches suivantes : + +- Importer les données dans Neo4J à l'aide de l'outil d'import : [`ìmport-tool`](http://neo4j.com/docs/operations-manual/current/tutorial/import-tool/). +- Implémenter l'Oracle de Bacon à l'aide de Neo4J dans la méthode `com.serli.oracle.of.bacon.repository.Neo4JRepository#getConnectionsToKevinBacon` +- Implémenter la gestion du last 10 search à l'aide de Redis dans la méthode `com.serli.oracle.of.bacon.repository.RedisRepository#getLastTenSearches` +- Importer les données à l'aide de ElasticSearch dans `com.serli.oracle.of.bacon.loader.elasticsearch.CompletionLoader` (alternativement vous pouvez importer les données avec le script node dans `script/insert.js`) (les liens suivants pourront vous aider : [search](https://www.elastic.co/guide/en/elasticsearch/reference/current/search.html), [mapping](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html) et [suggest](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters.html)) +- Implémenter la suggestion sur le nom des acteurs dans `com.serli.oracle.of.bacon.repository.ElasticSearchRepository#getActorsSuggests` + +L'évaluation de votre travail sera effectuée selon les critères suivants : + +- Bon fonctionnement (First make it work) +- Qualité de la solution implémentée (Then make it good) +- Qualité générale de votre code (et de vos commits, il ne faut pas pousser :smiley:) + +La livraison de votre travail s'effectue à l'aide d'une pull-request sur le repository https://github.com/nosql-bootcamp/oracle-of-bacon. + +**Vous devez commencer par forker le repository https://github.com/nosql-bootcamp/oracle-of-bacon** diff --git a/result.png b/result.png new file mode 100644 index 0000000000000000000000000000000000000000..f34d72e8518d90f9b16df6cc62b48c9377c4c32b GIT binary patch literal 84032 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

f~x) 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 Date: Wed, 24 Mar 2021 18:03:35 +0100 Subject: [PATCH 9/9] chore: add some main in modules to test custom inputs. --- .../serli/oracle/of/bacon/Application.java | 4 ++-- .../repository/ElasticSearchRepository.java | 12 ++++++++++ .../of/bacon/repository/Neo4JRepository.java | 8 +++++++ .../of/bacon/repository/RedisRepository.java | 23 +++++++++++++++++-- .../bacon/utils/{EnvUtils.java => Utils.java} | 8 +++++-- 5 files changed, 49 insertions(+), 6 deletions(-) rename oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/utils/{EnvUtils.java => Utils.java} (54%) diff --git a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/Application.java b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/Application.java index ee42296..217f841 100644 --- a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/Application.java +++ b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/Application.java @@ -3,7 +3,7 @@ import com.serli.oracle.of.bacon.api.APIEndPoint; import net.codestory.http.WebServer; -import static com.serli.oracle.of.bacon.utils.EnvUtils.getenv; +import static com.serli.oracle.of.bacon.utils.Utils.getenv; public class Application { @@ -13,7 +13,7 @@ public static void main(String[] args) { routes.add(new APIEndPoint()); }); - String port = getenv("PORT", "8000"); + String port = getenv("PORT", "8001"); webServer.start(Integer.valueOf(port)); } diff --git a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/ElasticSearchRepository.java b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/ElasticSearchRepository.java index ec333a7..3a43c44 100644 --- a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/ElasticSearchRepository.java +++ b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/ElasticSearchRepository.java @@ -2,6 +2,8 @@ import java.util.ArrayList; import java.util.List; + +import com.serli.oracle.of.bacon.utils.Utils; import org.apache.http.HttpHost; import org.elasticsearch.action.admin.indices.get.GetIndexRequest; import org.elasticsearch.action.search.SearchRequest; @@ -57,8 +59,18 @@ public List getActorsSuggests(String searchQuery) throws Exception { return ans; } for (SearchHit hit : response.getHits().getHits()) { + Utils.print("suggestion-elastic: ", hit.getSourceAsString()); ans.add(hit.getSourceAsString()); } return ans; } + + public static void main(String args[]){ + ElasticSearchRepository es = new ElasticSearchRepository(); + try { + es.getActorsSuggests("maria"); + } catch (Exception e) { + e.printStackTrace(); + } + } } diff --git a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/Neo4JRepository.java b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/Neo4JRepository.java index 9ac599d..2d3c6d7 100644 --- a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/Neo4JRepository.java +++ b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/Neo4JRepository.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.Map; +import com.serli.oracle.of.bacon.utils.Utils; import org.neo4j.driver.*; import org.neo4j.driver.types.Node; import org.neo4j.driver.types.Path; @@ -22,6 +23,7 @@ public List getConnections(String actorName) { List res = new ArrayList<>(); try (Session session = driver.session()) { + String query = "match p=(n:Actor)-[*]-(o:Movie) where n.name=$actorName return p"; Result result = session.run(query, parameters("actorName", actorName)); while (result.hasNext()) { @@ -158,4 +160,10 @@ public String toString() { "}\n"; } } + + public static void main(String args[]){ + Neo4JRepository neo = new Neo4JRepository(); + neo.connectionsToJson(neo.getConnections("Abadie, William")); + neo.connectionsToJson(neo.getSomeNodes()); + } } diff --git a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/RedisRepository.java b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/RedisRepository.java index f3f4602..7d18259 100644 --- a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/RedisRepository.java +++ b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/repository/RedisRepository.java @@ -1,9 +1,11 @@ package com.serli.oracle.of.bacon.repository; import java.sql.Timestamp; +import java.util.ArrayList; import java.util.Date; import java.util.List; +import com.serli.oracle.of.bacon.utils.Utils; import redis.clients.jedis.Jedis; public class RedisRepository { @@ -16,10 +18,27 @@ public RedisRepository() { public void insertSearch(String search){ // insert in a sorted set (timestamp: search) Timestamp ts = new Timestamp(new Date().getTime()); - jedis.zadd("search", ts.getTime(), search); + Utils.print("search-text", search + " at "+ ts.getTime()); + jedis.zadd("search", -ts.getTime(), search); } public List getLastNSearches( int n ) { - return (List) jedis.zrange("search",0, n); + List res = new ArrayList<>(); + for(String s: jedis.zrange("search",0, -1) ){ + res.add(s); + if(res.size()==n) return res; + Utils.print("last-searches", s); + } + return res; + } + + public static void main(String args[]){ + RedisRepository r = new RedisRepository(); + r.insertSearch("dark-vader"); + r.insertSearch("anakin-vader"); + r.insertSearch("luke-vader"); + r.insertSearch("ramona-vader"); + r.insertSearch("daniel-vader"); + r.getLastNSearches(10); } } diff --git a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/utils/EnvUtils.java b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/utils/Utils.java similarity index 54% rename from oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/utils/EnvUtils.java rename to oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/utils/Utils.java index 18ef1a4..0f0ea99 100644 --- a/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/utils/EnvUtils.java +++ b/oracle-of-bacon-backend/src/main/java/com/serli/oracle/of/bacon/utils/Utils.java @@ -1,9 +1,13 @@ package com.serli.oracle.of.bacon.utils; -public final class EnvUtils { - private EnvUtils(){} +public final class Utils { + private Utils(){} public static String getenv(String name, String defaultValue){ return System.getenv(name) != null ? System.getenv(name) : defaultValue; } + + public static void print(String msg, String content){ + System.out.println(msg + ":" + content); + } }