Bearloga has uploaded a new change for review.
https://gerrit.wikimedia.org/r/235137
Change subject: Initial commit
......................................................................
Initial commit
Includes: script for acquiring aggregated data and storing it on the
server and a basic Shiny dashboard for displaying that aggregated data
Change-Id: Ibd72fa7676f4c0a46cfcd9d82716969f226171ae
---
A README.md
A assets/dataviz.css
A assets/wdqs_basic.md
A data_retrieval/wdqs.R
A server.R
A twilightsparql.Rproj
A ui.R
A utils.R
A www/custom.css
A www/custom.js
10 files changed, 261 insertions(+), 0 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/wikimedia/discovery/twilightsparql
refs/changes/37/235137/1
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2a258f4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,19 @@
+## Quick start
+
+Install the dependencies:
+
+```
+$ R
+> install.packages(c("curl", "httpuv", "readr", "xts", "reshape2",
+ "RColorBrewer", "shiny", "shinydashboard", "dygraphs", "markdown",
+ "ggplot2", "toOrdinal", "dplyr"))
+```
+
+Run the server:
+
+```
+$ R
+> library(shiny)
+> runApp(launch.browser = 0)
+```
+
diff --git a/assets/dataviz.css b/assets/dataviz.css
new file mode 100644
index 0000000..fb0d105
--- /dev/null
+++ b/assets/dataviz.css
@@ -0,0 +1,3 @@
+.dygraph-legend {
+ background-color: #ECF0F5 !important;
+}
diff --git a/assets/wdqs_basic.md b/assets/wdqs_basic.md
new file mode 100644
index 0000000..e9714d4
--- /dev/null
+++ b/assets/wdqs_basic.md
@@ -0,0 +1,23 @@
+Wikidata Query Service (WDQS) usage
+=======
+
+**Requests** in *Daily WDQS usage* are the non-query requests made to `/` and
`/index.php`.
+
+**Events** in *Daily SparQL usage* are the `sparql-results` requests.
+
+Outages and inaccuracies
+------
+
+ * None so far!
+
+Questions, bug reports, and feature suggestions
+------
+For technical, non-bug questions, [email
Mikhail](mailto:[email protected]?subject=Dashboard%20Question). If you
experience a bug or notice something wrong or have a suggestion, [open a ticket
in Phabricator](https://phabricator.wikimedia.org/maniphest/task/create/) in
the Discovery board or [email
Dan](mailto:[email protected]?subject=Dashboard%20Question).
+
+<hr style="border-color: gray;">
+<p style="font-size: small; color: gray;">
+ <strong>Link to this dashboard:</strong>
+ <a href="http://searchdata.wmflabs.org/metrics/#wdqs_usage">
+ http://searchdata.wmflabs.org/metrics/#wdqs_usage
+ </a>
+</p>
diff --git a/data_retrieval/wdqs.R b/data_retrieval/wdqs.R
new file mode 100644
index 0000000..36bca99
--- /dev/null
+++ b/data_retrieval/wdqs.R
@@ -0,0 +1,86 @@
+#Config variables and setup
+options(scipen = 500,
+ q = "no")
+base_path <- "/a/aggregate-datasets/wdqs/"
+
+#Dependencies
+library(olivr)
+suppressPackageStartupMessages(library(data.table))
+
+if(!file.exists(base_path)){
+ dir.create(path = base_path)
+}
+
+#Conditional write; if the file exists, add x to the end. If it doesn't, write
an entirely new file.
+conditional_write <- function(x, file) {
+ if(file.exists(file)){
+ write.table(x, file, append = TRUE, sep = "\t", row.names = FALSE,
col.names = FALSE)
+ } else {
+ write.table(x, file, append = FALSE, sep = "\t", row.names = FALSE)
+ }
+}
+
+#Retrieves data for the WDQS stuff we care about, drops it in the
aggregate-datasets directory.
+#Should be run on stat1002, /not/ on the datavis machine.
+
+# Create a script that would produce raw data on usage of
+# - query.wikidata.org
+# - SPARQL endpoint: query.wikidata.org/bigdata/namespace/wdq/sparql
+
+#A function for creating a hive query aimed at the data from yesterday.
+# Central function
+main <- function(date = NULL) {
+
+ # Date handling
+ if(is.null(date)) {
+ date <- Sys.Date() - 1
+ }
+ subquery <- paste0(" WHERE year = ", lubridate::year(date),
+ " AND month = ", lubridate::month(date),
+ " AND day = ", lubridate::day(date), " ")
+
+ # Write query and dump to file
+ query <- paste0("USE wmf;
+ SELECT year, month, day,
+ FIND_IN_SET(uri_path,
'/bigdata/namespace/wdq/sparql,/,/index.php') AS uri_path,
+ IF(INSTR(uri_query, 'query') > 0, 'query', 'other') AS
uri_query,
+ IF(INSTR(content_type, 'sparql-results') > 0, 'sparql
results', 'other') AS content_type,
+ COUNT(*) AS n
+ FROM webrequest",
+ subquery,
+ "AND webrequest_source = 'misc' AND FIND_IN_SET(http_status,
'200,301,302,303') > 0
+ GROUP BY year, month, day,
+ FIND_IN_SET(uri_path,
'/bigdata/namespace/wdq/sparql,/,/index.php'),
+ IF(INSTR(uri_query, 'query') > 0, 'query', 'other'),
+ IF(INSTR(content_type, 'sparql-results') > 0, 'sparql
results', 'other');")
+ query_dump <- tempfile()
+ cat(query, file = query_dump)
+
+ # Query
+ results_dump <- tempfile()
+ system(paste0("export HADOOP_HEAPSIZE=1024 && hive -f ", query_dump, " > ",
results_dump))
+ results <- read.delim(results_dump, sep = "\t", quote = "", as.is = TRUE,
header = TRUE)
+ file.remove(query_dump, results_dump)
+
+ results$uri_path <- factor(results$uri_path, 0:3, c("other",
"/bigdata/namespace/wdq/sparql", "/", "/index.php"))
+
+ output <- data.frame(timestamp = as.Date(paste(results$year, results$month,
results$day, sep = "-")),
+ path = results$uri_path,
+ query = results$uri_query,
+ content = results$content_type,
+ events = results$n,
+ stringsAsFactors = FALSE)
+
+ # Write out
+ conditional_write(output, file.path(base_path, "wdqs_aggregates.tsv"))
+
+}
+
+# Backlog (start date: 2015-07-28):
+# backlog <- function(days) {
+# for (i in days:1) try(main(Sys.Date() - i), silent = TRUE)
+# }; backlog(30) # as of 2015-08-27
+
+#Run and kill
+main()
+q(save = "no")
diff --git a/server.R b/server.R
new file mode 100644
index 0000000..4beba98
--- /dev/null
+++ b/server.R
@@ -0,0 +1,47 @@
+source("utils.R")
+
+existing_date <- (Sys.Date() - 1)
+
+read_wdqs <- function(){
+ data <- download_set("wdqs_aggregates.tsv")
+ data <- data[order(data$timestamp),]
+ wdqs_usage <<- data
+ return(invisible())
+}
+
+shinyServer(function(input, output) {
+
+ if(Sys.Date() != existing_date){
+ read_wdqs()
+ existing_date <<- Sys.Date()
+ }
+
+ output$wdqs_usage_plot <- renderDygraph({
+ wdqs_usage %>%
+ dplyr::filter(path %in% c("/", "/index.php") & query == "other") %>%
+ dplyr::group_by(timestamp) %>%
+ summarise(total = sum(events)) %>%
+ # tidyr::spread(query, total) %>%
+ { xts(., order.by = .$timestamp) } %>%
+ dygraph(main = "Daily WDQS usage", group = "wdqs_basic",
+ xlab = "Date", ylab = "Requests") %>%
+ dyOptions(strokeWidth = 3, colors = brewer.pal(3, "Set2")[1],
+ drawPoints = TRUE, pointSize = 3, labelsKMB = TRUE,
+ includeZero = TRUE) %>%
+ dyCSS(css = "./assets/dataviz.css")
+ })
+
+ output$sparql_usage_plot <- renderDygraph({
+ wdqs_usage %>%
+ dplyr::filter(path == "/bigdata/namespace/wdq/sparql" & content ==
"sparql results") %>%
+ dplyr::select(c(timestamp, events)) %>%
+ { xts(., order.by = .$timestamp) } %>%
+ dygraph(main = "Daily SparkQL usage", group = "wdqs_basic",
+ xlab = "Date", ylab = "Events") %>%
+ dyOptions(strokeWidth = 3, colors = brewer.pal(3, "Set2")[2],
+ drawPoints = TRUE, pointSize = 3, labelsKMB = TRUE,
+ includeZero = TRUE) %>%
+ dyCSS(css = "./assets/dataviz.css")
+ })
+
+})
\ No newline at end of file
diff --git a/twilightsparql.Rproj b/twilightsparql.Rproj
new file mode 100644
index 0000000..d063e8b
--- /dev/null
+++ b/twilightsparql.Rproj
@@ -0,0 +1,13 @@
+Version: 1.0
+
+RestoreWorkspace: Default
+SaveWorkspace: Default
+AlwaysSaveHistory: Default
+
+EnableCodeIndexing: Yes
+UseSpacesForTab: Yes
+NumSpacesForTab: 2
+Encoding: UTF-8
+
+RnwWeave: knitr
+LaTeX: pdfLaTeX
diff --git a/ui.R b/ui.R
new file mode 100644
index 0000000..b69bb5f
--- /dev/null
+++ b/ui.R
@@ -0,0 +1,29 @@
+library(shiny)
+library(shinydashboard)
+library(dygraphs) # optional, used for dygraphs
+
+# Header elements for the visualization
+header <- dashboardHeader(title = "Wikidata Query Service", disable = FALSE)
+
+# Sidebar elements for the search visualizations
+sidebar <- dashboardSidebar(
+ tags$head(
+ tags$link(rel = "stylesheet", type = "text/css", href = "custom.css"),
+ tags$script(src = "custom.js")
+ ),
+ sidebarMenu(
+ menuItem(text = "WDQS Usage", tabName = "wdqs_usage")
+ ) # /sidebarMenu
+) # /dashboardSidebar
+
+#Body elements for the search visualizations.
+body <- dashboardBody(
+ tabItems(
+ tabItem(tabName = "wdqs_usage",
+ fluidRow(column(dygraphOutput("wdqs_usage_plot"), width = 6),
+ column(dygraphOutput("sparql_usage_plot"), width = 6)),
+ includeMarkdown("./assets/wdqs_basic.md"))
+ ) # /tabItems
+) # /dashboardBody
+
+dashboardPage(header, sidebar, body, skin = "purple")
\ No newline at end of file
diff --git a/utils.R b/utils.R
new file mode 100644
index 0000000..2d4f780
--- /dev/null
+++ b/utils.R
@@ -0,0 +1,18 @@
+#Dependent libs
+library(readr)
+library(xts)
+library(reshape2)
+library(RColorBrewer)
+
+#Utility functions for handling particularly common tasks
+download_set <- function(dataset){
+ con <- url(paste0("http://datasets.wikimedia.org/aggregate-datasets/wdqs/",
dataset))
+ return(readr::read_delim(con, delim = "\t"))
+}
+
+# This function takes a number and returns a compressed string (e.g. 1624 =>
1.6K or 2K, depending on round.by)
+compress <- function(x, round.by = 2) {
+ # by StackOverflow user 'BondedDust' : http://stackoverflow.com/a/28160474
+ div <- findInterval(as.numeric(gsub("\\,", "", x)), c(1, 1e3, 1e6, 1e9,
1e12) )
+ paste(round( as.numeric(gsub("\\,","",x))/10^(3*(div-1)), round.by),
c("","K","M","B","T")[div], sep = "" )
+}
diff --git a/www/custom.css b/www/custom.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/www/custom.css
diff --git a/www/custom.js b/www/custom.js
new file mode 100644
index 0000000..4569dbe
--- /dev/null
+++ b/www/custom.js
@@ -0,0 +1,23 @@
+$(function() {
+
+ // Enables linking to specific tabs:
+ if (window.location.hash){
+ var hash = $.trim(window.location.hash);
+ var tab = decodeURI(hash.substring(1, 100));
+ $('a[data-value=\"'+tab+'\"]').click();
+ }
+ // Usage: append the tabName to the URL after the hash.
+
+ // Enables clicking on a kpi summary value box to view the time series:
+ $('div[id^=kpi_summary_box_]').click(function(){
+ var parent_id = $(this).closest('div').attr('id');
+ var parent_target = parent_id.replace('_summary_box', '');
+ $('a[data-value=\"'+parent_target+'\"]').click();
+ });
+
+ // Visual feedback that the value box is now something you can click:
+ $('div[id^=kpi_summary_box_]').hover(function() {
+ $(this).css('cursor','pointer');
+ });
+
+});
--
To view, visit https://gerrit.wikimedia.org/r/235137
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ibd72fa7676f4c0a46cfcd9d82716969f226171ae
Gerrit-PatchSet: 1
Gerrit-Project: wikimedia/discovery/twilightsparql
Gerrit-Branch: master
Gerrit-Owner: Bearloga <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits