aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/edu/brown/cs/student/term/DatabaseQuerier.java4
-rw-r--r--src/main/java/edu/brown/cs/student/term/Main.java129
-rw-r--r--src/main/java/edu/brown/cs/student/term/hub/HubSearch.java103
-rw-r--r--src/main/java/edu/brown/cs/student/term/hub/LinkMapper.java92
4 files changed, 302 insertions, 26 deletions
diff --git a/src/main/java/edu/brown/cs/student/term/DatabaseQuerier.java b/src/main/java/edu/brown/cs/student/term/DatabaseQuerier.java
index 1bb49c7..7e9a184 100644
--- a/src/main/java/edu/brown/cs/student/term/DatabaseQuerier.java
+++ b/src/main/java/edu/brown/cs/student/term/DatabaseQuerier.java
@@ -85,8 +85,4 @@ public class DatabaseQuerier{
return trades;
}
-
-
-
-
}
diff --git a/src/main/java/edu/brown/cs/student/term/Main.java b/src/main/java/edu/brown/cs/student/term/Main.java
index 31bf7a3..b8ff2c9 100644
--- a/src/main/java/edu/brown/cs/student/term/Main.java
+++ b/src/main/java/edu/brown/cs/student/term/Main.java
@@ -13,6 +13,59 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
+import spark.*;
+import spark.template.freemarker.FreeMarkerEngine;
+
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+import com.google.common.collect.ImmutableMap;
+
+import freemarker.template.Configuration;
+
+//fix
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.sql.ResultSet;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.*;
+import com.google.common.collect.ImmutableMap;
+import com.google.gson.Gson;
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
+import spark.ExceptionHandler;
+import spark.ModelAndView;
+import spark.QueryParamsMap;
+import spark.Request;
+import spark.Response;
+import spark.Route;
+import spark.Filter;
+import spark.Spark;
+import spark.TemplateViewRoute;
+import spark.template.freemarker.FreeMarkerEngine;
+
+import freemarker.template.Configuration;
+
+
+import org.json.JSONObject;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+
/**
* The Main class of our project. This is where execution begins.
*/
@@ -44,8 +97,7 @@ public final class Main {
OptionSet options = parser.parse(args);
if (options.has("gui")) {
- //do a gui type thing
- //runSparkServer((int) options.valueOf("port"));
+ runSparkServer((int) options.valueOf("port"));
}
HashMap<String, Command> commandHashMap = new HashMap<>();
@@ -55,5 +107,78 @@ public final class Main {
repl.runREPL();
}
+ private static FreeMarkerEngine createEngine() {
+ Configuration config = new Configuration();
+ File templates = new File("src/main/resources/spark/template/freemarker");
+ try {
+ config.setDirectoryForTemplateLoading(templates);
+ } catch (IOException ioe) {
+ System.out.printf("ERROR: Unable use %s for template loading.%n",
+ templates);
+ System.exit(1);
+ }
+ return new FreeMarkerEngine(config);
+ }
+
+ public void runSparkServer(int port) {
+ Spark.port(port);
+ Spark.externalStaticFileLocation("src/main/resources/static");
+ Spark.exception(Exception.class, new ExceptionPrinter());
+
+ Spark.options("/*",
+ (request, response) -> {
+
+ String accessControlRequestHeaders = request
+ .headers("Access-Control-Request-Headers");
+ if (accessControlRequestHeaders != null) {
+ response.header("Access-Control-Allow-Headers",
+ accessControlRequestHeaders);
+ }
+
+ String accessControlRequestMethod = request
+ .headers("Access-Control-Request-Method");
+ if (accessControlRequestMethod != null) {
+ response.header("Access-Control-Allow-Methods",
+ accessControlRequestMethod);
+ }
+
+ return "OK";
+ });
+
+ Spark.before((request, response) -> response.header("Access-Control-Allow-Origin", "*"));
+ Spark.get("/data", new DataHandler());
+ }
+
+
+ private static class DataHandler implements Route {
+
+ @Override
+ public Object handle(Request request, Response response) throws Exception {
+ String str = request.body();
+ JSONObject json = new JSONObject(str);
+
+ String startLat = json.getString("srclat");
+ return "ok";
+ }
+ }
+
+ /**
+ * Display an error page when an exception occurs in the server.
+ *
+ */
+ private static class ExceptionPrinter implements ExceptionHandler {
+ @Override
+ public void handle(Exception e, Request req, Response res) {
+ res.status(500);
+ StringWriter stacktrace = new StringWriter();
+ try (PrintWriter pw = new PrintWriter(stacktrace)) {
+ pw.println("<pre>");
+ e.printStackTrace(pw);
+ pw.println("</pre>");
+ }
+ res.body(stacktrace.toString());
+ }
+ }
+
} \ No newline at end of file
diff --git a/src/main/java/edu/brown/cs/student/term/hub/HubSearch.java b/src/main/java/edu/brown/cs/student/term/hub/HubSearch.java
index 4c382ec..4d5755c 100644
--- a/src/main/java/edu/brown/cs/student/term/hub/HubSearch.java
+++ b/src/main/java/edu/brown/cs/student/term/hub/HubSearch.java
@@ -1,7 +1,101 @@
package edu.brown.cs.student.term.hub;
+import edu.brown.cs.student.term.DatabaseQuerier;
+import edu.brown.cs.student.term.repl.commands.SetupCommand;
+
+import java.time.Instant;
+import java.util.*;
+
public class HubSearch {
+ LinkMapper mapper;
+ Map<Holder, Set<Holder>> followerToLeaderMap = new HashMap<>();
+
+ //TODO: Make this just take in a map from holder -> set of holder
+ public HubSearch(LinkMapper mapper){
+ this.mapper = mapper;
+ }
+
+ //TODO: reevaluate this basic version and tweak to customize
+ public Map<Holder, Double> runHubSearch(Instant start, Instant end){
+ followerToLeaderMap = mapper.makeFollowerLinks(start, end);
+ int numHolders = followerToLeaderMap.size();
+ List<Holder> holders = new ArrayList<>(followerToLeaderMap.keySet());
+ double[] weights = new double[numHolders];
+ double[] rank = new double[numHolders];
+ double[] rankPrime = new double[numHolders];
+ Arrays.fill(rankPrime, 1.0 / numHolders);
+
+ while(!withinDistance(rank, rankPrime)){
+ rank = Arrays.copyOf(rankPrime, rankPrime.length);
+ //calculating hub rank for ith holder
+ for(int i = 0; i < numHolders; i++){
+ rankPrime[i] = 0;
+ //iterating through all holders to calculate hub rank
+ for(int j = 0; j < numHolders; j++){
+ double weightIJ = getWeight(holders.get(i), holders.get(j), numHolders);
+ rankPrime[i] += (weightIJ * rank[j]);
+ }
+ }
+ }
+
+ //potentially should change this to be a map from holder id => double?
+ Map<Holder, Double> hubRankMap = new HashMap<>();
+
+ for(int i = 0; i < rankPrime.length; i++){
+ hubRankMap.put(holders.get(i), rankPrime[i]);
+ }
+
+ return hubRankMap;
+ }
+
+ private double getWeight(Holder leader, Holder follower, int numHolders){
+
+ //dampening factor
+ double damp = 0.15;
+ /*
+ In normal page rank:
+ links is the pages that k links to, if k links to j, then
+ we want to add some weight to j from k, but that
+ weight is diluted by the number of links that k has
+ in general because we don't want to count a bunch of links
+ from a page as highly as one targeted link from one page to another
+
+ In Hub Search
+ leader = j, follower = k, if follower links to (follows) leader,
+ then we want to add some weight from follower to leader,
+ but should that weight be diluted by the number of people
+ who followed leader or the number of people who follower followed
+ --- probably the second option ;( */
+ Set<Holder> peopleFollowed = followerToLeaderMap.get(follower);
+ int numberFollowed = peopleFollowed.size();
+
+ if(peopleFollowed.contains(leader)){
+ return ((damp / numHolders) + (1 - damp) * (1.0 / numberFollowed));
+ } else if(numberFollowed == 0){
+ return ((damp / numHolders) + (1 - damp) * (1.0 / numHolders));
+ } else {
+ return (damp / numHolders);
+ }
+ }
+
+ private boolean withinDistance(double[] r, double[] rPrime){
+ double sum = 0.0;
+ for(int i = 0; i < r.length; i++){
+ sum += Math.pow((r[i] - rPrime[i]), 2);
+ }
+
+ return sum <= 0.001;
+ }
+
+
+
+
+
+
+
+
+
/*
def pageRank(pList: List[Page]): mutable.HashMap[Int, Double] = {
val n = pList.length
@@ -41,5 +135,14 @@ public class HubSearch {
(0.15 / n)
}
}
+
+ def distance(r1: Array[Double], r2: Array[Double]): Boolean = {
+ var sum = 0.0
+ for (i <- 0 to r1.length - 1) {
+ sum = sum + Math.pow((r1(i) - r2(i)), 2)
+ }
+ sum <= .001
+
+ }
*/
}
diff --git a/src/main/java/edu/brown/cs/student/term/hub/LinkMapper.java b/src/main/java/edu/brown/cs/student/term/hub/LinkMapper.java
index f4ec0a7..8bc8cf9 100644
--- a/src/main/java/edu/brown/cs/student/term/hub/LinkMapper.java
+++ b/src/main/java/edu/brown/cs/student/term/hub/LinkMapper.java
@@ -1,7 +1,6 @@
package edu.brown.cs.student.term.hub;
import edu.brown.cs.student.term.DatabaseQuerier;
-import edu.brown.cs.student.term.repl.commands.SetupCommand;
import edu.brown.cs.student.term.trade.Trade;
import java.sql.SQLException;
@@ -10,30 +9,23 @@ import java.util.*;
public class LinkMapper {
+ //TODO: Review what we actually need in here
//not strictly necessary but may be nice to maintain
private List<List<Trade>> allTrades = new ArrayList<>();
- private Map<Holder, List<Trade>> personToTradesMap = new HashMap<>();
- private Map<Holder, List<Holder>> personToFollowers = new HashMap<>();
+ private Map<Holder, Set<Holder>> followerToLeaders = new HashMap<>();
private DatabaseQuerier databaseQuerier;
public LinkMapper(DatabaseQuerier db){
this.databaseQuerier = db;
}
- /**
- * Returns the person => trades map as is, does not update it
- * @return person to trades map
- */
- public Map<Holder, List<Trade>> getPersonToTradesMap() {
- return personToTradesMap;
- }
/**
- * Returns the person => follower map as is, does not update it
+ * Returns the follower => leaders map as is, does not update it
* @return person to follower map
*/
- public Map<Holder, List<Holder>> getPersonToFollowers() {
- return personToFollowers;
+ public Map<Holder, Set<Holder>> getFollowerToLeaders() {
+ return followerToLeaders;
}
/**
@@ -41,20 +33,17 @@ public class LinkMapper {
* in the same time period
* @return the newly updated link map
*/
- public Map<Holder, List<Holder>> makeFollowerLinks(Instant start, Instant end){
+ public Map<Holder, Set<Holder>> makeFollowerLinks(Instant start, Instant end){
if(databaseQuerier != null){
try{
List<List<Trade>> allTrades = databaseQuerier.getAllTradesByStock(start, end);
//reset the map to be blank
- personToFollowers = new HashMap<>();
+ followerToLeaders = new HashMap<>();
for(List<Trade> tradeList : allTrades){
convertTradeListToFollowerMap(tradeList);
}
- //System.out.println(personToFollowers.toString());
- System.out.println("num people in map: " + personToFollowers.size());
-
} catch(SQLException e) {
System.out.println("ERROR: SQL Error while retrieving trade list");
}
@@ -62,9 +51,12 @@ public class LinkMapper {
System.out.println("ERROR: No database loaded in yet");
}
- return personToFollowers;
+ return followerToLeaders;
}
+
+ //TODO: Try to create both leader => follower and follower => leader map at once
+ //only if necessary tho!
private void convertTradeListToFollowerMap(List<Trade> tradeList){
List<Holder> holderList = new ArrayList<>();
@@ -73,6 +65,66 @@ public class LinkMapper {
holderList.add(trade.getHolder());
}
+ //Set<Holder> followers = new HashSet<>(holderList);
+ Set<Holder> encountered = new HashSet<>();
+
+ //[bob, george, jane, bob, mary]
+ for(Holder current: holderList){
+ //only want to use first instance of a holder to dictate who they followed
+ //for instance, if the person whose at the front buys again, they probably
+ //didn't follow the people in between, just wanted to buy again
+ if(!encountered.contains(current)){
+ if(followerToLeaders.containsKey(current)){
+ //TODO: this probably makes it O(n^2), might want to optimize later
+ followerToLeaders.get(current).addAll(encountered);
+ } else {
+ Set<Holder> currentLeaders = new HashSet<>(encountered);
+ followerToLeaders.put(current, currentLeaders);
+ }
+ encountered.add(current);
+ }
+ }
+
+ }
+
+ //This code creates a leader => follower map!
+ /*private void convertTradeListToFollowerMap(List<Trade> tradeList){
+ List<Holder> holderList = new ArrayList<>();
+
+ //gets in order list of people
+ for (Trade trade : tradeList) {
+ holderList.add(trade.getHolder());
+ }
+
+ Set<Holder> followers = new HashSet<>(holderList);
+ Set<Holder> encountered = new HashSet<>();
+
+ for(Holder current: holderList){
+ //want to check if we've already gotten followers for this trade for this holder
+ if(!encountered.contains(current)){
+ encountered.add(current);
+ followers.remove(current);
+ if(personToFollowers.containsKey(current)){
+ //TODO: this probably makes it O(n^2), might want to optimize later
+ personToFollowers.get(current).addAll(followers);
+ } else {
+ Set<Holder> currentFollowers = new HashSet<>(followers);
+ personToFollowers.put(current, currentFollowers);
+ }
+ }
+ }
+ }*/
+
+
+ //Old version using lists of followers, allowing for duplicates
+ /*private void convertTradeListToFollowerMap(List<Trade> tradeList){
+ List<Holder> holderList = new ArrayList<>();
+
+ //gets in order list of people
+ for (Trade trade : tradeList) {
+ holderList.add(trade.getHolder());
+ }
+
Set<Holder> followers = new HashSet<>(holderList);
Set<Holder> encountered = new HashSet<>();
@@ -90,5 +142,5 @@ public class LinkMapper {
}
}
}
- }
+ }*/
}