Graph database Analysis of the Steam Network
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

435 lines
12 KiB

  1. package net.jrtechs.www.graphDB;
  2. import net.jrtechs.www.SteamAPI.SteamConnectionException;
  3. import net.jrtechs.www.model.Game;
  4. import net.jrtechs.www.model.Player;
  5. import net.jrtechs.www.SteamAPI.APIConnection;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. import java.util.stream.Collectors;
  9. /**
  10. * Does graph based operations with {@link Player}
  11. * and
  12. *
  13. * @author Jeffery Russell 5-26-17
  14. */
  15. public class SteamGraph
  16. {
  17. public static String KEY_PLAYER = "player";
  18. public static String KEY_CRAWLED_STATUS = "crawled";
  19. public static String KEY_CRAWLED_GAME_STATUS = "crawled_game";
  20. /** Connection to the graph server */
  21. private GraphConnection con;
  22. /** Connection to steam api */
  23. private APIConnection api;
  24. /**
  25. * Constructs object with a graph connection
  26. * and a steam api connection
  27. */
  28. public SteamGraph()
  29. {
  30. this.con = new GraphConnection();
  31. this.api = new APIConnection();
  32. }
  33. /**
  34. * Checks if a player is already in the graph
  35. *
  36. * @param id steam id of player
  37. * @return
  38. */
  39. private boolean alreadyInGraph(String id)
  40. {
  41. System.out.println("Checking id:" + id);
  42. return !con.getTraversal()
  43. .V().hasLabel(SteamGraph.KEY_PLAYER)
  44. .has(Player.KEY_STEAM_ID, id)
  45. .toList().isEmpty();
  46. }
  47. /**
  48. * Inserts a player vertex into the graph
  49. *
  50. * @param
  51. */
  52. private void insertPlayerIntoGraph(Player p, boolean check)
  53. {
  54. try
  55. {
  56. if(!check || !this.alreadyInGraph(p.getId()))
  57. {
  58. System.out.println("inserting " + p.getName() + " into graph");
  59. this.con.getTraversal()
  60. .addV(SteamGraph.KEY_PLAYER)
  61. .property(Player.KEY_USERNAME, p.getName())
  62. .property(SteamGraph.KEY_CRAWLED_STATUS, 0)
  63. .property(SteamGraph.KEY_CRAWLED_GAME_STATUS, 0)
  64. .property(Player.KEY_STEAM_ID, p.getId())
  65. .property(Player.KEY_AVATAR, p.getAvatar())
  66. .property(Player.KEY_REAL_NAME, p.getRealName())
  67. .property(Player.KEY_TIME_CREATED, p.getTimeCreated())
  68. .id().next();
  69. }
  70. }
  71. catch (Exception e)
  72. {
  73. e.printStackTrace();
  74. }
  75. }
  76. private boolean gameAlreadyInGraph(Integer id)
  77. {
  78. return !con.getTraversal()
  79. .V().hasLabel(Game.KEY_DB)
  80. .has(Game.KEY_STEAM_GAME_ID, id)
  81. .toList().isEmpty();
  82. }
  83. private void insertGameForPlayerToGraph(String id, Game g)
  84. {
  85. if(!gameAlreadyInGraph(g.getAppID()))// check if game is already in graph
  86. {
  87. //insert game into graph
  88. this.con.getTraversal()
  89. .addV(Game.KEY_DB)
  90. .property(Game.KEY_STEAM_GAME_ID, g.getAppID())
  91. .property(Game.KEY_GAME_NAME, g.getName())
  92. .property(Game.KEY_GAME_ICON, g.getIcon())
  93. .property(Game.KEY_GAME_LOGO, g.getLogo())
  94. .id().next();
  95. }
  96. // insert connection from player to game
  97. this.con.getTraversal()
  98. .V()
  99. .hasLabel(SteamGraph.KEY_PLAYER)
  100. .has(Player.KEY_STEAM_ID, id)
  101. .as("p")
  102. .V().hasLabel(Game.KEY_DB)
  103. .has(Game.KEY_STEAM_GAME_ID, g.getAppID())
  104. .as("g")
  105. .addE(Game.KEY_RELATIONSHIP)
  106. .from("p").to("g")
  107. .property(Game.KEY_PLAY_TIME, g.getTimePlayed())
  108. .id().next();
  109. }
  110. /**
  111. * Checks if a friend-friend edge is already in the
  112. * graph
  113. *
  114. * @param p1
  115. * @param p2
  116. * @return
  117. */
  118. private boolean edgeAlreadyInGraph(String p1, String p2)
  119. {
  120. try
  121. {
  122. return !this.con.getTraversal()
  123. .V().hasLabel(SteamGraph.KEY_PLAYER)
  124. .has(Player.KEY_STEAM_ID, p1)
  125. .both()
  126. .has(Player.KEY_STEAM_ID, p2)
  127. .toList().isEmpty();
  128. }
  129. catch(Exception e)
  130. {
  131. return false;
  132. }
  133. }
  134. /**
  135. * Inserts a edge between two players into the graph
  136. *
  137. * @param p1
  138. * @param p2
  139. */
  140. private void insertEdgeIntoGraph(String p1, String p2)
  141. {
  142. try
  143. {
  144. if(!this.edgeAlreadyInGraph(p1, p2))
  145. {
  146. System.out.println("Inserting edge: " + p1 + ":" + p2);
  147. this.con.getTraversal()
  148. .V()
  149. .hasLabel(SteamGraph.KEY_PLAYER)
  150. .has(Player.KEY_STEAM_ID, p1)
  151. .as("p1")
  152. .V().hasLabel(SteamGraph.KEY_PLAYER)
  153. .has(Player.KEY_STEAM_ID, p2)
  154. .as("p2")
  155. .addE(Player.KEY_FRIENDS)
  156. .from("p1").to("p2").id().next();
  157. }
  158. }
  159. catch (Exception e)
  160. {
  161. e.printStackTrace();
  162. }
  163. }
  164. /**
  165. * determines if a player has been indexed for friends yet
  166. *
  167. * @param id
  168. * @return
  169. */
  170. private boolean playerFriendsAlreadyIndexed(String id)
  171. {
  172. return playerPropertyIndexed(id, SteamGraph.KEY_CRAWLED_STATUS);
  173. }
  174. private boolean playerGamesAlreadyIndexed(String id)
  175. {
  176. return playerPropertyIndexed(id, SteamGraph.KEY_CRAWLED_GAME_STATUS);
  177. }
  178. /**
  179. * determines if a player has been indexed yet
  180. *
  181. * @param id
  182. * @return
  183. */
  184. private boolean playerPropertyIndexed(String id, String key)
  185. {
  186. try
  187. {
  188. return this.con.getTraversal()
  189. .V().hasLabel(SteamGraph.KEY_PLAYER)
  190. .has(Player.KEY_STEAM_ID, id)
  191. .has(key, 0)
  192. .toList().isEmpty();
  193. }
  194. catch(Exception e)
  195. {
  196. e.printStackTrace();
  197. }
  198. return true;
  199. }
  200. private void updateCrawledStatusFriends(String id)
  201. {
  202. updateCrawledStatus(id, SteamGraph.KEY_CRAWLED_STATUS);
  203. }
  204. private void updateCrawledStatusGames(String id)
  205. {
  206. updateCrawledStatus(id, SteamGraph.KEY_CRAWLED_GAME_STATUS);
  207. }
  208. private void updateCrawledStatus(String id, String key)
  209. {
  210. try
  211. {
  212. this.con.getTraversal().V()
  213. .hasLabel(SteamGraph.KEY_PLAYER)
  214. .has(Player.KEY_STEAM_ID, id)
  215. .property(key, 1).id().next();
  216. }
  217. catch (Exception e)
  218. {
  219. e.printStackTrace();
  220. }
  221. }
  222. /**
  223. * Fetches the name of the player from the graph database
  224. *
  225. * @param id
  226. * @return
  227. */
  228. private Player getPlayerFromGraph(String id)
  229. {
  230. return new Player(this.con.getTraversal().V()
  231. .hasLabel(SteamGraph.KEY_PLAYER)
  232. .has(Player.KEY_STEAM_ID, id)
  233. .valueMap()
  234. .toStream().findFirst().get());
  235. }
  236. /**
  237. * Fetches a list of friends from the graph database
  238. *
  239. * @param id steam id
  240. * @return list of friends
  241. */
  242. private List<Player> getFriendsFromGraph(String id)
  243. {
  244. System.out.println("fetching friends from graph");
  245. return new ArrayList<Player>()
  246. {{
  247. con.getTraversal().V()
  248. .hasLabel(SteamGraph.KEY_PLAYER)
  249. .has(Player.KEY_STEAM_ID, id)
  250. .outE()
  251. .inV()
  252. .hasLabel(SteamGraph.KEY_PLAYER)
  253. .valueMap()
  254. .toStream()
  255. .forEach(r ->
  256. add(new Player(r)));
  257. }};
  258. }
  259. private List<Game> getPlayerGamesFromGraph(String id)
  260. {
  261. System.out.println("fetching games from graph");
  262. return new ArrayList<Game>()
  263. {{
  264. con.getTraversal().V()
  265. .hasLabel(SteamGraph.KEY_PLAYER)
  266. .has(Player.KEY_STEAM_ID, id)
  267. .outE()
  268. .inV()
  269. .hasLabel(Game.KEY_DB)
  270. .valueMap()
  271. .toStream().forEach(r ->
  272. add(new Game(r)));
  273. }};
  274. }
  275. /**
  276. * tells api to get this dude's friends list
  277. *
  278. * @param id
  279. */
  280. private void indexPersonFriends(String id)
  281. {
  282. System.out.println("indexing " + id);
  283. List<String> friendsIds = this.api.getFriends(id);
  284. //find ones not in database
  285. List<String> notInDatabase = friendsIds
  286. .stream()
  287. .filter(p -> !alreadyInGraph(p))
  288. .collect(Collectors.toList());
  289. this.api.getPlayers(notInDatabase)
  290. .forEach(p ->
  291. insertPlayerIntoGraph(p, false));
  292. friendsIds.forEach(s->
  293. this.insertEdgeIntoGraph(id, s));
  294. this.updateCrawledStatusFriends(id);
  295. this.con.commit();
  296. }
  297. private List<Game> indexPersonsGames(String id)
  298. {
  299. System.out.println("indexing games for " + id);
  300. List<Game> games = this.api.getGames(id);
  301. games.forEach(g -> insertGameForPlayerToGraph(id, g));
  302. this.updateCrawledStatusGames(id);
  303. this.con.commit();
  304. return games;
  305. }
  306. public List<Game> getGameList(String id)
  307. {
  308. return this.playerGamesAlreadyIndexed(id) ?
  309. this.getPlayerGamesFromGraph(id) :
  310. this.indexPersonsGames(id);
  311. }
  312. /**
  313. * Fetches a player from the graph with all of its friends
  314. *
  315. * @param id
  316. * @return
  317. */
  318. public Player getPlayer(String id)
  319. {
  320. Player p;
  321. if(this.alreadyInGraph(id)) // yay
  322. {
  323. p = this.getPlayerFromGraph(id);
  324. if(!this.playerFriendsAlreadyIndexed(id)) //must index the person
  325. {
  326. this.indexPersonFriends(id);
  327. }
  328. p.setFriends(this.getFriendsFromGraph(id));
  329. }
  330. else //smh, shouldn't happen frequently
  331. {
  332. System.out.println("brand spanking new request " + id);
  333. try
  334. {
  335. p = this.api.getSingle(id);
  336. this.insertPlayerIntoGraph(p, false);
  337. this.indexPersonFriends(id);
  338. p.setFriends(this.getFriendsFromGraph(id));
  339. }
  340. catch (SteamConnectionException e)
  341. {
  342. e.printStackTrace();
  343. return null;
  344. }
  345. }
  346. return p;
  347. }
  348. public void close()
  349. {
  350. try
  351. {
  352. this.con.closeConnection();
  353. }
  354. catch (Exception e)
  355. {
  356. e.printStackTrace();
  357. }
  358. }
  359. /**
  360. *
  361. * @param args
  362. */
  363. public static void main(String[] args)
  364. {
  365. SteamGraph graph = new SteamGraph();
  366. graph.getPlayer("76561198188400721");
  367. graph.getGameList("76561198188400721");
  368. // //graph.getPlayer("76561198068098265").getFriends().stream().forEach(System.out::println);
  369. //// graph.indexPersonFriends("76561198188400721");
  370. // graph.indexPersonsGames("76561198188400721");
  371. // System.out.println(graph.getGameList("76561198188400721"));
  372. // System.out.println(graph.getPlayer("76561198188400721"));
  373. graph.close();
  374. //
  375. // Player base = graph.getPlayer(args[0]);
  376. //
  377. // int debth = Integer.valueOf(args[1]);
  378. //
  379. // graph.insertIntoGraph(base, debth);
  380. }
  381. }