Unique players / day query

This commit is contained in:
Rsl1122 2019-08-13 14:18:29 +03:00
parent 01fb2debb6
commit cb626145fe
5 changed files with 106 additions and 19 deletions

View File

@ -17,11 +17,9 @@
package com.djrapitops.plan.data.store.mutators;
import com.djrapitops.plan.utilities.html.graphs.line.Point;
import com.djrapitops.plugin.utilities.Verify;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TimeZone;
import java.util.*;
import java.util.stream.Collectors;
public class MutatorFunctions {
@ -38,6 +36,32 @@ public class MutatorFunctions {
.collect(Collectors.toList());
}
public static NavigableMap<Long, Integer> addMissing(NavigableMap<Long, Integer> points, long accuracy, Integer replacement) {
if (Verify.isEmpty(points)) return points;
NavigableMap<Long, Integer> filled = new TreeMap<>();
Long lastX = null;
for (Map.Entry<Long, Integer> point : points.entrySet()) {
long date = point.getKey();
if (lastX != null && date - lastX > accuracy) {
addMissing(lastX, date, filled, accuracy, replacement);
}
lastX = date;
filled.put(point.getKey(), point.getValue());
}
return filled;
}
private static void addMissing(long from, long to, NavigableMap<Long, Integer> points, long accuracy, Integer replacement) {
long iterate = from;
while (iterate < to) {
points.put(iterate, replacement);
iterate += accuracy;
}
}
public static int average(Map<Long, Integer> map) {
return (int) map.values().stream()
.mapToInt(i -> i)

View File

@ -18,12 +18,15 @@ package com.djrapitops.plan.db.access.queries.analysis;
import com.djrapitops.plan.db.access.Query;
import com.djrapitops.plan.db.access.QueryStatement;
import com.djrapitops.plan.db.sql.parsing.Sql;
import com.djrapitops.plan.db.sql.tables.SessionsTable;
import com.djrapitops.plan.db.sql.tables.UserInfoTable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.NavigableMap;
import java.util.TreeMap;
import java.util.UUID;
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
@ -65,6 +68,49 @@ public class PlayerCountQueries {
return queryPlayerCount(sql, after, before, serverUUID);
}
/**
* Fetch a EpochMs - Count map of unique players on a server.
*
* @param after After epoch ms
* @param before Before epoch ms
* @param timeZoneOffset Offset from {@link java.util.TimeZone#getOffset(long)}, applied to the dates before grouping.
* @param serverUUID UUID of the Plan server
* @return Map: Epoch ms (Accuracy of a day) - How many unique players played that day
*/
public static Query<NavigableMap<Long, Integer>> uniquePlayerCounts(long after, long before, long timeZoneOffset, UUID serverUUID) {
return database -> {
Sql sql = database.getType().getSql();
String selectUniquePlayersPerDay = SELECT +
sql.dateToEpochSecond(sql.dateToDayStamp(sql.epochSecondToDate('(' + SessionsTable.SESSION_START + "+?)/1000"))) +
"*1000 as date," +
"COUNT(DISTINCT " + SessionsTable.USER_UUID + ") as player_count" +
FROM + SessionsTable.TABLE_NAME +
WHERE + SessionsTable.SESSION_END + "<=?" +
AND + SessionsTable.SESSION_START + ">=?" +
AND + SessionsTable.SERVER_UUID + "=?" +
GROUP_BY + "date";
return database.query(new QueryStatement<NavigableMap<Long, Integer>>(selectUniquePlayersPerDay, 100) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setLong(1, timeZoneOffset);
statement.setLong(2, before);
statement.setLong(3, after);
statement.setString(4, serverUUID.toString());
}
@Override
public NavigableMap<Long, Integer> processResults(ResultSet set) throws SQLException {
NavigableMap<Long, Integer> uniquePerDay = new TreeMap<>();
while (set.next()) {
uniquePerDay.put(set.getLong("date"), set.getInt("player_count"));
}
return uniquePerDay;
}
});
};
}
public static Query<Integer> newPlayerCount(long after, long before, UUID serverUUID) {
String sql = SELECT + "COUNT(" + UserInfoTable.USER_UUID + ") as player_count" +
FROM + UserInfoTable.TABLE_NAME +

View File

@ -17,13 +17,20 @@
package com.djrapitops.plan.system.json;
import com.djrapitops.plan.data.container.Ping;
import com.djrapitops.plan.data.store.mutators.*;
import com.djrapitops.plan.data.store.mutators.MutatorFunctions;
import com.djrapitops.plan.data.store.mutators.PingMutator;
import com.djrapitops.plan.data.store.mutators.PlayersMutator;
import com.djrapitops.plan.data.store.mutators.TPSMutator;
import com.djrapitops.plan.data.store.objects.DateMap;
import com.djrapitops.plan.data.time.WorldTimes;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.queries.analysis.ActivityIndexQueries;
import com.djrapitops.plan.db.access.queries.analysis.PlayerCountQueries;
import com.djrapitops.plan.db.access.queries.containers.ServerPlayerContainersQuery;
import com.djrapitops.plan.db.access.queries.objects.*;
import com.djrapitops.plan.db.access.queries.objects.GeoInfoQueries;
import com.djrapitops.plan.db.access.queries.objects.PingQueries;
import com.djrapitops.plan.db.access.queries.objects.TPSQueries;
import com.djrapitops.plan.db.access.queries.objects.WorldTimesQueries;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.settings.config.PlanConfig;
import com.djrapitops.plan.system.settings.paths.TimeSettings;
@ -86,13 +93,20 @@ public class GraphJSONParser {
public String uniqueAndNewGraphJSON(UUID serverUUID) {
Database db = dbSystem.getDatabase();
LineGraphFactory lineGraphs = graphs.line();
SessionsMutator sessionsMutator = new SessionsMutator(db.query(SessionQueries.fetchSessionsOfServerFlat(serverUUID)))
.filterSessionsBetween(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(180L), System.currentTimeMillis());
long now = System.currentTimeMillis();
long halfYearAgo = now - TimeUnit.DAYS.toMillis(180L);
NavigableMap<Long, Integer> uniquePerDay = db.query(
PlayerCountQueries.uniquePlayerCounts(halfYearAgo, now, timeZone.getOffset(now), serverUUID)
);
PlayersMutator playersMutator = new PlayersMutator(db.query(new ServerPlayerContainersQuery(serverUUID)))
.filterRegisteredBetween(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(180L), System.currentTimeMillis());
.filterRegisteredBetween(halfYearAgo, now);
return "{\"uniquePlayers\":" +
lineGraphs.lineGraph(MutatorFunctions.toPointsWithRemovedOffset(sessionsMutator.uniqueJoinsPerDay(timeZone), timeZone)).toHighChartsSeries() +
lineGraphs.lineGraph(
MutatorFunctions.toPointsWithRemovedOffset(
MutatorFunctions.addMissing(uniquePerDay, TimeUnit.DAYS.toMillis(1L), 0),
timeZone
)).toHighChartsSeries() +
",\"newPlayers\":" +
lineGraphs.lineGraph(MutatorFunctions.toPointsWithRemovedOffset(playersMutator.newPerDay(timeZone), timeZone)).toHighChartsSeries() +
'}';
@ -100,14 +114,17 @@ public class GraphJSONParser {
public String serverCalendarJSON(UUID serverUUID) {
Database db = dbSystem.getDatabase();
SessionsMutator sessionsMutator = new SessionsMutator(db.query(SessionQueries.fetchSessionsOfServerFlat(serverUUID)))
.filterSessionsBetween(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(730L), System.currentTimeMillis());
long now = System.currentTimeMillis();
long twoYearsAgo = now - TimeUnit.DAYS.toMillis(730L);
NavigableMap<Long, Integer> uniquePerDay = db.query(
PlayerCountQueries.uniquePlayerCounts(twoYearsAgo, now, timeZone.getOffset(now), serverUUID)
);
PlayersMutator playersMutator = new PlayersMutator(db.query(new ServerPlayerContainersQuery(serverUUID)));
return "{\"data\":" +
graphs.calendar().serverCalendar(
playersMutator,
sessionsMutator.uniqueJoinsPerDay(timeZone),
uniquePerDay,
playersMutator.newPerDay(timeZone)
).toCalendarSeries() +
",\"firstDay\":" + 1 + '}';

View File

@ -25,8 +25,8 @@ import com.djrapitops.plan.utilities.formatting.Formatters;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.SortedMap;
import java.util.TimeZone;
import java.util.TreeMap;
/**
* Factory class for different objects representing HTML calendars.
@ -60,8 +60,8 @@ public class CalendarFactory {
public ServerCalendar serverCalendar(
PlayersMutator mutator,
TreeMap<Long, Integer> uniquePerDay,
TreeMap<Long, Integer> newPerDay
SortedMap<Long, Integer> uniquePerDay,
SortedMap<Long, Integer> newPerDay
) {
return new ServerCalendar(
mutator, uniquePerDay, newPerDay,

View File

@ -33,8 +33,8 @@ import java.util.*;
public class ServerCalendar {
private final PlayersMutator mutator;
private final TreeMap<Long, Integer> uniquePerDay;
private final TreeMap<Long, Integer> newPerDay;
private final SortedMap<Long, Integer> uniquePerDay;
private final SortedMap<Long, Integer> newPerDay;
private final Formatter<Long> iso8601Formatter;
private final Formatter<Long> timeAmountFormatter;
@ -42,7 +42,7 @@ public class ServerCalendar {
private final TimeZone timeZone;
ServerCalendar(
PlayersMutator mutator, TreeMap<Long, Integer> uniquePerDay, TreeMap<Long, Integer> newPerDay,
PlayersMutator mutator, SortedMap<Long, Integer> uniquePerDay, SortedMap<Long, Integer> newPerDay,
Formatter<Long> iso8601Formatter,
Formatter<Long> timeAmountFormatter,
Theme theme,