{"id":52187,"date":"2025-07-16T00:00:00","date_gmt":"2025-07-16T07:00:00","guid":{"rendered":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/blog\/sports-analytics\/"},"modified":"2025-07-16T00:00:00","modified_gmt":"2025-07-16T07:00:00","slug":"sports-analytics","status":"publish","type":"post","link":"https:\/\/griddb.net\/en\/blog\/sports-analytics\/","title":{"rendered":"Sports Analytics with GridDB"},"content":{"rendered":"<h2><strong>Introduction<\/strong><\/h2>\n<p>In modern sports, data-driven decision-making has become essential for gaining a competitive edge. Every step, shot, or lap generates a stream of events that require high-speed ingestion, efficient storage, and rapid querying\u2014challenges that traditional relational databases struggle to handle at scale. To address this, organizations are increasingly looking into alternatives.<\/p>\n<p>GridDB, a highly scalable and efficient time-series database, is designed to manage large volumes of continuously generated data such as above. By leveraging GridDB, teams can analyze critical performance metrics such as player speed, fatigue levels, and tactical positioning over time. These insights enable coaches and analysts to make informed decisions on game tactics, substitutions, and training regimens based on real-time and historical data.<\/p>\n<p>In this article, we explore how GridDB, integrated within a Spring Boot application, can be used for a soccer analytics use case\u2014optimizing player substitutions and refining game strategies with data-driven precision.<\/p>\n<p><strong>Understanding the Use Case<\/strong><\/p>\n<p>A single soccer match generates hundreds of timestamped events\u2014such as a midfielder\u2019s pass at a given time e.g. 20:05:32 or a striker\u2019s shot at time 20:10:15\u2014each enriched with outcomes and metadata. The sequential nature of this data reveals crucial patterns, like player fatigue or shifts in attacking momentum, that static analyses often miss. For engineers, the challenge lies in efficiently managing this high-speed, high-volume data stream.<\/p>\n<p>To simulate this type of data, we will use <a href=\"https:\/\/github.com\/statsbomb\/open-data\/blob\/master\/data\/events\/15946.json\">events\/15946.json<\/a> dataset from <a href=\"https:\/\/statsbomb.com\/what-we-do\/hub\/free-data\/\">StatsBomb<\/a>, which logs an entire match\u2019s events\u2014including passes, shots, and tackles\u2014with millisecond precision. Our Spring Boot application, powered by GridDB, will focus on:<\/p>\n<ul>\n<li><strong>Performance Tracking<\/strong>: Monitoring pass accuracy to detect signs of fatigue.<\/li>\n<li><strong>Strategy Optimization<\/strong>: Analyzing shot frequency to uncover attacking opportunities.<\/li>\n<\/ul>\n<h2>Setting Up GridDB Cluster and Spring Boot Integration<\/h2>\n<h3><strong>Project Structure<\/strong><\/h3>\n<p>Here&#8217;s a suggested project structure for this application:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">\u251c\u2500\u2500\u2500my-griddb-app\n\u2502   \u2502   pom.xml\n\u2502   \u2502   \n\u2502   \u251c\u2500\u2500\u2500src\n\u2502   \u2502   \u251c\u2500\u2500\u2500main\n\u2502   \u2502   \u2502   \u251c\u2500\u2500\u2500java\n\u2502   \u2502   \u2502   \u2502   \u2514\u2500\u2500\u2500mycode\n\u2502   \u2502   \u2502   \u2502       \u2502   MySpringBootApplication.java\n\u2502   \u2502   \u2502   \u2502       \u2502   \n\u2502   \u2502   \u2502   \u2502       \u251c\u2500\u2500\u2500config\n\u2502   \u2502   \u2502   \u2502       \u2502       GridDBConfig.txt\n\u2502   \u2502   \u2502   \u2502       \u2502\n\u2502   \u2502   \u2502   \u2502       \u251c\u2500\u2500\u2500controller\n\u2502   \u2502   \u2502   \u2502       \u2502       MatchEventsController.java\n\u2502   \u2502   \u2502   \u2502       \u2502\n\u2502   \u2502   \u2502   \u2502       \u2514\u2500\u2500\u2500service\n\u2502   \u2502   \u2502   \u2502               MatchEventsService.java\n\u2502   \u2502   \u2502   \u2502               MetricsCollectionService.java\n\u2502   \u2502   \u2502   \u2502               RestTemplateConfig.java\n\u2502   \u2502   \u2502   \u2502\n\u2502   \u2502   \u2502   \u2514\u2500\u2500\u2500resources\n\u2502   \u2502   \u2502       \u2502   application.properties\n\u2502   \u2502   \u2502       \u2502\n\u2502   \u2502   \u2502       \u2514\u2500\u2500\u2500templates\n\u2502   \u2502   \u2502               pass-accuracy-graph.html<\/code><\/pre>\n<\/div>\n<p>This structure separates controllers, models, repositories, services, and the application entry point into distinct layers, enhancing modularity and maintainability. It can be further customized based on individual requirements.<\/p>\n<h3><strong>Set Up GridDB Cloud<\/strong><\/h3>\n<p>For this exercise, we will be using GridDB Cloud version. Start by visiting the <a href=\"https:\/\/griddb.net\/en\/\">GridDB Cloud<\/a> portal and &#91;signing up&#93;(<a href=\"https:\/\/form.ict-toshiba.jp\/download_form_griddb_cloud_freeplan_e?utm_source=griddbnet&amp;utm_medium=topbanner\">GridDB Cloud Free Plan | TOSHIBA DIGITAL SOLUTIONS CORPORATION<\/a>) for an account. <a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/07\/logo.webp\"><img fetchpriority=\"high\" decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/07\/logo.webp\" alt=\"\" width=\"1280\" height=\"149\" class=\"aligncenter size-full wp-image-32149\" srcset=\"\/wp-content\/uploads\/2025\/07\/logo.webp 1280w, \/wp-content\/uploads\/2025\/07\/logo-300x35.webp 300w, \/wp-content\/uploads\/2025\/07\/logo-1024x119.webp 1024w, \/wp-content\/uploads\/2025\/07\/logo-768x89.webp 768w, \/wp-content\/uploads\/2025\/07\/logo-600x70.webp 600w\" sizes=\"(max-width: 1280px) 100vw, 1280px\" \/><\/a><\/p>\n<p>Based on requirements, either the free plan or a paid plan can be selected for broader access. After registration ,an email will be sent containing essential details, including the Web API URL and login credentials.<\/p>\n<p>Once the login details are received, log in to the Management GUI to access the cloud instance.<\/p>\n<h4>Create Database Credentials<\/h4>\n<p>Before interacting with the database, we must create a database user:<\/p>\n<ul>\n<li>\n<p><strong>Navigate to Security Settings<\/strong>: In the Management GUI, go to the &#8220;GridDB Users&#8221; tab.<\/p>\n<\/li>\n<li>\n<p><strong>Create a Database User<\/strong>: Click &#8220;Create Database User,&#8221; enter a username and password, and save the credentials. For example, set the username as soccer_admin and a strong password.<\/p>\n<\/li>\n<li>\n<p><strong>Store Credentials Securely<\/strong>: These will be used in your application to authenticate with GridDB Cloud.<\/p>\n<\/li>\n<\/ul>\n<h4>Set Allowed IP Addresses<\/h4>\n<p>To restrict access to authorized sources, configure the allowed IP settings:<\/p>\n<ul>\n<li><strong>Navigate to Security Settings<\/strong>: In the Management GUI, go to the &#8220;Network Access&#8221; tab and locate the &#8220;Allowed IP&#8221; section and add the .<\/li>\n<li><strong>Add IP Addresses<\/strong>: For development, you can temporarily add your local machine\u2019s IP.<\/li>\n<\/ul>\n<h4> <\/h4>\n<h3><strong>Add POM Dependency<\/strong><\/h3>\n<p>Here&#8217;s an example of how to configure the dependency in the<code>pom.xml<\/code> file:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">&lt;project \n  xmlns_xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\n  xsi_schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/maven-v4_0_0.xsd\"&gt;\n  &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;\n  &lt;groupId&gt;com.example&lt;\/groupId&gt;\n  &lt;artifactId&gt;my-griddb-app&lt;\/artifactId&gt;\n  &lt;version&gt;1.0-SNAPSHOT&lt;\/version&gt;\n  &lt;name&gt;my-griddb-app&lt;\/name&gt;\n  &lt;url&gt;http:\/\/maven.apache.org&lt;\/url&gt;\n\n  &lt;parent&gt;\n    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n    &lt;artifactId&gt;spring-boot-starter-parent&lt;\/artifactId&gt;\n    &lt;version&gt;3.2.4&lt;\/version&gt;\n    &lt;relativePath \/&gt; &lt;!-- lookup parent from repository --&gt;\n  &lt;\/parent&gt;\n\n  &lt;properties&gt;\n    &lt;maven.compiler.source&gt;17&lt;\/maven.compiler.source&gt;\n    &lt;maven.compiler.target&gt;17&lt;\/maven.compiler.target&gt;\n  &lt;\/properties&gt;\n\n  &lt;dependencies&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n      &lt;artifactId&gt;spring-boot-starter-actuator&lt;\/artifactId&gt;\n    &lt;\/dependency&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;junit&lt;\/groupId&gt;\n      &lt;artifactId&gt;junit&lt;\/artifactId&gt;\n      &lt;version&gt;3.8.1&lt;\/version&gt;\n      &lt;scope&gt;test&lt;\/scope&gt;\n    &lt;\/dependency&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n      &lt;artifactId&gt;spring-boot-starter-web&lt;\/artifactId&gt;\n      &lt;exclusions&gt;\n        &lt;exclusion&gt;\n          &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n          &lt;artifactId&gt;spring-boot-starter-logging&lt;\/artifactId&gt;\n        &lt;\/exclusion&gt;\n      &lt;\/exclusions&gt;\n    &lt;\/dependency&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n      &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt;\n      &lt;scope&gt;test&lt;\/scope&gt;\n    &lt;\/dependency&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n      &lt;artifactId&gt;spring-boot-starter-thymeleaf&lt;\/artifactId&gt;\n    &lt;\/dependency&gt;\n    &lt;!-- JSON processing --&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.glassfish.jersey.core&lt;\/groupId&gt;\n      &lt;artifactId&gt;jersey-client&lt;\/artifactId&gt;\n      &lt;version&gt;2.35&lt;\/version&gt;\n    &lt;\/dependency&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.json&lt;\/groupId&gt;\n      &lt;artifactId&gt;json&lt;\/artifactId&gt;\n      &lt;version&gt;20210307&lt;\/version&gt;\n    &lt;\/dependency&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;com.fasterxml.jackson.core&lt;\/groupId&gt;\n      &lt;artifactId&gt;jackson-databind&lt;\/artifactId&gt;\n      &lt;version&gt;2.15.0&lt;\/version&gt; &lt;!-- or the latest version --&gt;\n    &lt;\/dependency&gt;\n    &lt;!-- Lombok --&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.projectlombok&lt;\/groupId&gt;\n      &lt;artifactId&gt;lombok&lt;\/artifactId&gt;\n      &lt;optional&gt;true&lt;\/optional&gt;\n    &lt;\/dependency&gt;\n  &lt;\/dependencies&gt;\n&lt;\/project&gt;<\/code><\/pre>\n<\/div>\n<h3><strong>Technical Implementation<\/strong><\/h3>\n<p>Implementing a soccer analytics solution with GridDB and Spring Boot involves three key steps:<\/p>\n<ol>\n<li><strong>Ingesting<\/strong> the StatsBomb <strong>events\/15946.json<\/strong> dataset into GridDB.<\/li>\n<li><strong>Querying<\/strong> the data to extract time-series metrics.<\/li>\n<li><strong>Visualizing<\/strong> the results to generate actionable insights.<\/li>\n<\/ol>\n<p>Below, we explore each phase in detail, showcasing GridDB\u2019s time-series capabilities and its seamless integration within a Spring Boot architecture.<\/p>\n<h4><strong>Step 1: Data Ingestion<\/strong><\/h4>\n<p>The <strong>events\/15946.json<\/strong> file logs a sequence of match events\u2014passes, shots, tackles\u2014each record containing essential fields such as:<\/p>\n<ul>\n<li><strong>Timestamp<\/strong> (e.g., <code>\"2021-06-11T20:05:32.456\"<\/code>)<\/li>\n<li><strong>Player Name<\/strong> (<code>player.name<\/code>)<\/li>\n<li><strong>Event Type<\/strong> (<code>type.name<\/code>)<\/li>\n<li><strong>Outcome<\/strong> (e.g., <code>pass.outcome.name<\/code> as <code>\"Complete\"<\/code>, <code>shot.outcome.name<\/code> as <code>\"Goal\"<\/code>)<\/li>\n<\/ul>\n<p>To efficiently store and query this data in <strong>GridDB<\/strong>, we first need define a <strong>time-series container<\/strong> in GridDb cloud as below.<\/p>\n<h5><strong>Container Setup<\/strong><\/h5>\n<p>We define a container name <strong>match_events<\/strong> in <strong>GridDB Cloud<\/strong> using the <strong>time-series type<\/strong> with <code>timestamp<\/code> as the <strong>row key<\/strong>.<\/p>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/07\/Cluster.webp\"><img decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/07\/Cluster.webp\" alt=\"\" width=\"1920\" height=\"1031\" class=\"aligncenter size-full wp-image-32147\" srcset=\"\/wp-content\/uploads\/2025\/07\/Cluster.webp 1920w, \/wp-content\/uploads\/2025\/07\/Cluster-300x161.webp 300w, \/wp-content\/uploads\/2025\/07\/Cluster-1024x550.webp 1024w, \/wp-content\/uploads\/2025\/07\/Cluster-768x412.webp 768w, \/wp-content\/uploads\/2025\/07\/Cluster-1536x825.webp 1536w, \/wp-content\/uploads\/2025\/07\/Cluster-600x322.webp 600w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>Next, we will create schema which will includes the following columns:<\/p>\n<ul>\n<li><code>timestamp<\/code> (<strong>TIMESTAMP<\/strong>, <strong>NOT NULL<\/strong>, <strong>Row Key<\/strong>)<\/li>\n<li><code>player_name<\/code> (<strong>STRING<\/strong>)<\/li>\n<li><code>event_type<\/code> (<strong>STRING<\/strong>)<\/li>\n<li><code>event_outcome<\/code> (<strong>STRING<\/strong>)<\/li>\n<li><code>minute<\/code> (<strong>INTEGER<\/strong>)<\/li>\n<li><code>second<\/code> (<strong>INTEGER<\/strong>)<\/li>\n<li><code>team_name<\/code> (<strong>STRING<\/strong>)<\/li>\n<\/ul>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/07\/schema.webp\"><img decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/07\/schema.webp\" alt=\"\" width=\"1920\" height=\"1031\" class=\"aligncenter size-full wp-image-32150\" srcset=\"\/wp-content\/uploads\/2025\/07\/schema.webp 1920w, \/wp-content\/uploads\/2025\/07\/schema-300x161.webp 300w, \/wp-content\/uploads\/2025\/07\/schema-1024x550.webp 1024w, \/wp-content\/uploads\/2025\/07\/schema-768x412.webp 768w, \/wp-content\/uploads\/2025\/07\/schema-1536x825.webp 1536w, \/wp-content\/uploads\/2025\/07\/schema-600x322.webp 600w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>Afterwards we implement <code>MetricsCollectionService<\/code>which fetches data from JSON file and pushing the data in database.<\/p>\n<p>Here the implentation of <code>MetricCollectionService.java<\/code> :<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-java\">package mycode.service;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\nimport org.springframework.stereotype.Service;\nimport org.springframework.beans.factory.annotation.Value;\nimport java.io.OutputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.time.LocalDate;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Scanner;\n\n@Service\npublic class MetricsCollectionService {\n  private static String gridDBRestUrl;\n  private static String gridDBApiKey;\n\n  @Value(\"${griddb.rest.url}\")\n  public void setgridDBRestUrl(String in) {\n    gridDBRestUrl = in;\n  }\n\n  @Value(\"${griddb.api.key}\")\n  public void setgridDBApiKey(String in) {\n    gridDBApiKey = in;\n  }\n\n  public void collect() {\n    try {\n      \/\/ Fetch JSON Data from GitHub\n      String jsonResponse = fetchJSONFromGitHub(\n          \"https:\/\/raw.githubusercontent.com\/statsbomb\/open-data\/master\/data\/events\/15946.json\");\n      JSONArray events = new JSONArray(jsonResponse);\n\n      \/\/ Process and Send Data to GridDB Cloud\n      sendBatchToGridDB(events);\n\n    } catch (Exception e) {\n      e.printStackTrace();\n    }\n  }\n\n  private static String fetchJSONFromGitHub(String urlString) throws Exception {\n    URL url = new URL(urlString);\n    HttpURLConnection conn = (HttpURLConnection) url.openConnection();\n    conn.setRequestMethod(\"GET\");\n    conn.setRequestProperty(\"Accept\", \"application\/json\");\n\n    if (conn.getResponseCode() != 200) {\n      throw new RuntimeException(\"Failed to fetch data: HTTP error code : \" + conn.getResponseCode());\n    }\n\n    Scanner scanner = new Scanner(url.openStream());\n    StringBuilder response = new StringBuilder();\n    while (scanner.hasNext()) {\n      response.append(scanner.nextLine());\n    }\n    scanner.close();\n    return response.toString();\n  }\n\n  private static void sendBatchToGridDB(JSONArray events) {\n    JSONArray batchData = new JSONArray();\n    boolean startProcessing = false;\n    for (int i = 0; i &lt; events.length(); i++) {\n      JSONObject event = events.getJSONObject(i);\n      JSONArray row = new JSONArray();\n\n      if (event.has(\"index\") && event.getInt(\"index\") == 10) {\n        startProcessing = true;\n      }\n\n      if (!startProcessing) {\n        continue; \/\/ Skip records until we reach index == 7\n      }\n\n      \/\/ Extract and format fields\n      String formattedTimestamp = formatTimestamp(event.optString(\"timestamp\", null));\n      row.put(formattedTimestamp);\n      row.put(event.optJSONObject(\"player\") != null ? event.getJSONObject(\"player\").optString(\"name\", null) : null);\n      row.put(event.optJSONObject(\"type\") != null ? event.getJSONObject(\"type\").optString(\"name\", null) : null);\n\n      JSONObject passOutcome = event.optJSONObject(\"pass\");\n      JSONObject shotOutcome = event.optJSONObject(\"shot\");\n      if (passOutcome == null && shotOutcome == null) {\n        continue;\n      }\n\n      if (passOutcome != null) {\n        if (passOutcome.has(\"outcome\")) {\n          row.put(passOutcome.getJSONObject(\"outcome\").optString(\"name\", null));\n        } else {\n          row.put(JSONObject.NULL);\n        }\n      } else if (shotOutcome != null) {\n        if (shotOutcome.has(\"outcome\")) {\n          row.put(shotOutcome.getJSONObject(\"outcome\").optString(\"name\", null));\n        } else {\n          row.put(JSONObject.NULL);\n        }\n      } else {\n        row.put(JSONObject.NULL);\n      }\n\n      row.put(event.optInt(\"minute\", -1));\n      row.put(event.optInt(\"second\", -1));\n      row.put(event.optJSONObject(\"team\") != null ? event.getJSONObject(\"team\").optString(\"name\", null) : null);\n\n      batchData.put(row);\n    }\n\n    sendPutRequest(batchData);\n  }\n\n  private static String formatTimestamp(String inputTimestamp) {\n    try {\n      String todayDate = LocalDate.now().format(DateTimeFormatter.ISO_DATE);\n      return todayDate + \"T\" + inputTimestamp + \"Z\";\n    } catch (Exception e) {\n      return \"null\"; \/\/ Default if parsing fails\n    }\n  }\n\n  private static void sendPutRequest(JSONArray batchData) {\n    try {\n      URL url = new URL(gridDBRestUrl);\n      HttpURLConnection conn = (HttpURLConnection) url.openConnection();\n      conn.setDoOutput(true);\n      conn.setRequestMethod(\"PUT\");\n      conn.setRequestProperty(\"Content-Type\", \"application\/json\");\n      conn.setRequestProperty(\"Authorization\", gridDBApiKey);\n      \/\/ Encode username and password for Basic Auth\n\n      \/\/ Send JSON Data\n      OutputStream os = conn.getOutputStream();\n      os.write(batchData.toString().getBytes());\n      os.flush();\n\n      int responseCode = conn.getResponseCode();\n      if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED) {\n        System.out.println(\"Batch inserted successfully.\");\n      } else {\n        System.out.println(\"Failed to insert batch. Response: \" + responseCode);\n      }\n\n      conn.disconnect();\n    } catch (Exception e) {\n      e.printStackTrace();\n    }\n  }\n\n}<\/code><\/pre>\n<\/div>\n<h4>Ingestion Logic<\/h4>\n<p>This steps involves fetching data from GridDB using the REST API and grouping it into 5-minute intervals.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-java\">package mycode.service;\n\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\nimport org.springframework.stereotype.Service;\nimport java.net.URI;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpRequest;\nimport java.net.http.HttpResponse;\nimport java.util.HashMap;\nimport java.util.Map;\n\n@Service\npublic class MatchEventsService {\n\n  private static final String GRIDDB_URL = \"https:\/\/cloud5114.griddb.com:443\/griddb\/v2\/gs_clustermfcloud5114\/dbs\/9UkMCtv4\/containers\/match_events\/rows\";\n  private static final String AUTH_HEADER = \"Basic TTAyY...lhbEAx\";\n\n  private final HttpClient httpClient = HttpClient.newHttpClient();\n  private final ObjectMapper objectMapper = new ObjectMapper();\n\n  public Map&lt;Integer, Integer> getPassCountByFiveMin(String playerName) {\n    try {\n      \/\/ Build the HTTP request based on your curl\n      HttpRequest request = HttpRequest.newBuilder()\n          .uri(URI.create(GRIDDB_URL))\n          .header(\"Content-Type\", \"application\/json\")\n          .header(\"Authorization\", AUTH_HEADER)\n          .POST(HttpRequest.BodyPublishers.ofString(\"{\"offset\": 0, \"limit\": 55555}\"))\n          .build();\n\n      \/\/ Fetch the response\n      HttpResponse&lt;string> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());\n      JsonNode rootNode = objectMapper.readTree(response.body());\n      JsonNode rows = rootNode.get(\"rows\");\n\n      \/\/ Process data: count passes every 5 minutes\n      Map&lt;Integer, Integer> passCountByFiveMin = new HashMap&lt;>();\n\n      for (JsonNode row : rows) {\n        String currentPlayer = row.get(1).asText();\n        String eventType = row.get(2).asText();\n        int minute = row.get(4).asInt();\n\n        if (playerName.equals(currentPlayer) && \"Pass\".equals(eventType)) {\n          \/\/ Group by 5-minute intervals (0-4, 5-9, 10-14, etc.)\n          int fiveMinInterval = (minute \/ 5) * 5;\n          passCountByFiveMin.merge(fiveMinInterval, 1, Integer::sum);\n        }\n      }\n\n      return passCountByFiveMin;\n\n    } catch (Exception e) {\n      e.printStackTrace();\n      return new HashMap&lt;>();\n    }\n  }\n}&lt;\/string><\/code><\/pre>\n<\/div>\n<h6>Step 3: Visualization<\/h6>\n<p>To deliver insights, Spring Boot exposes REST endpoints via a @RestController:<\/p>\n<ul>\n<li>\n<p><strong>Endpoints<\/strong>: \/api\/pass-accuracy\/{player} returns a JSON array of {time, accuracy} pairs; \/api\/shot-frequency\/{team} returns {time, shots}.<\/p>\n<\/li>\n<li>\n<p><strong>Implementation<\/strong>: The controller calls the query service, maps GridDB results to DTOs, and serializes them with Spring\u2019s Jackson integration.<\/p>\n<\/li>\n<\/ul>\n<div class=\"clipboard\">\n<pre><code class=\"language-java\">package mycode.controller;\n\n\nimport mycode.service.MatchEventsService;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.Map;\n\n@Controller\npublic class MatchEventsController {\n\n  @Autowired\n  private MatchEventsService matchEventsService;\n\n  @GetMapping(\"\/pass-accuracy\/{playerName}\")\n  public String getPassCountEveryFiveMin(@PathVariable String playerName, Model model) {\n    Map&lt;Integer, Integer> passCountByFiveMin = matchEventsService.getPassCountByFiveMin(playerName);\n\n    \/\/ Prepare data for the chart\n    model.addAttribute(\"playerName\", playerName);\n    model.addAttribute(\"timeIntervals\", passCountByFiveMin.keySet().stream().sorted().toList());\n    model.addAttribute(\"passCounts\", passCountByFiveMin.values());\n\n    return \"pass-accuracy-graph\"; \/\/ Thymeleaf template name\n  }\n}<\/code><\/pre>\n<\/div>\n<h6> <\/h6>\n<h3>Running the Project<\/h3>\n<p>To run the project, execute the following command to build and run our application:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">mvn clean install && mvn spring-boot:run \u00a0<\/code><\/pre>\n<\/div>\n<h3>Accessing the Dashboard<\/h3>\n<p>After launching the application, open a web browser and navigate to: <code>http:\/\/localhost:9090\/pass-accuracy\/{{player name}}<\/code>.<\/p>\n<p>For example,<\/p>\n<p>http:\/\/localhost:9090\/pass-accuracy\/Lionel%20Andr%C3%A9s%20Messi%20Cuccittini<\/p>\n<p>This visualization displays a chart representing pass accuracy trends over time.<\/p>\n<p>It provides insights into the player&#8217;s fatigue levels over time and their overall activity on the field.<\/p>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/07\/graph.webp\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/07\/graph.webp\" alt=\"\" width=\"1920\" height=\"1031\" class=\"aligncenter size-full wp-image-32148\" srcset=\"\/wp-content\/uploads\/2025\/07\/graph.webp 1920w, \/wp-content\/uploads\/2025\/07\/graph-300x161.webp 300w, \/wp-content\/uploads\/2025\/07\/graph-1024x550.webp 1024w, \/wp-content\/uploads\/2025\/07\/graph-768x412.webp 768w, \/wp-content\/uploads\/2025\/07\/graph-1536x825.webp 1536w, \/wp-content\/uploads\/2025\/07\/graph-600x322.webp 600w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>Similarly various insights can be generated from this saved data, providing valuable analytics for team performance and decision-making. For example,<\/p>\n<ul>\n<li>\n<p><strong>Player Pass Accuracy Over Time<\/strong><\/p>\n<ul>\n<li>\n<p><strong>Data<\/strong>: Count of &#8220;Pass&#8221; events with outcome.name = &#8220;Complete&#8221; vs. &#8220;Incomplete&#8221; per player, bucketed by 5-minute intervals.<\/p>\n<\/li>\n<li>\n<p><strong>Visualization<\/strong>: Line graph with time (x-axis) and pass accuracy percentage (y-axis) for a key player (e.g., a midfielder).<\/p>\n<\/li>\n<li>\n<p><strong>Insight<\/strong>: If pass accuracy drops below 70% late in the game (e.g., after minute 70), the player may be fatigued\u2014time for a substitution.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Graph: Goal Proximity Over Time<\/strong><\/p>\n<ul>\n<li>\n<p><strong>Data<\/strong>: Count of &#8220;Shot&#8221; events with shot.outcome.name = &#8220;Goal&#8221; or near-miss outcomes (e.g., &#8220;Off Target&#8221;), bucketed by 10-minute intervals.<\/p>\n<\/li>\n<li>\n<p><strong>Visualization<\/strong>: Stacked bar graph with time (x-axis) and shot outcomes (y-axis).<\/p>\n<\/li>\n<li>\n<p><strong>Insight<\/strong>: Periods with frequent near-misses (e.g., minute 30-40) suggest missed opportunities\u2014adjust tactics to capitalize on pressure.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3><strong>Conclusion:<\/strong><\/h3>\n<p>As demonstrated, GridDB efficiently processes the timestamped complexity of soccer events, delivering structured insights with precision. Integrated within a Spring Boot application, its high-performance ingestion, optimized time-series indexing, and rapid querying capabilities enable the extraction of actionable metrics from StatsBomb data\u2014identifying player fatigue and strategic opportunities with millisecond accuracy.<\/p>\n<p>As sports technology continues to evolve, such implementations highlight the critical role of specialized databases in unlocking the full potential of temporal data.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction In modern sports, data-driven decision-making has become essential for gaining a competitive edge. Every step, shot, or lap generates a stream of events that require high-speed ingestion, efficient storage, and rapid querying\u2014challenges that traditional relational databases struggle to handle at scale. To address this, organizations are increasingly looking into alternatives. GridDB, a highly scalable [&hellip;]<\/p>\n","protected":false},"author":41,"featured_media":52188,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[121],"tags":[],"class_list":["post-52187","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Sports Analytics with GridDB | GridDB: Open Source Time Series Database for IoT<\/title>\n<meta name=\"description\" content=\"Introduction In modern sports, data-driven decision-making has become essential for gaining a competitive edge. Every step, shot, or lap generates a\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/griddb.net\/en\/blog\/sports-analytics\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Sports Analytics with GridDB | GridDB: Open Source Time Series Database for IoT\" \/>\n<meta property=\"og:description\" content=\"Introduction In modern sports, data-driven decision-making has become essential for gaining a competitive edge. Every step, shot, or lap generates a\" \/>\n<meta property=\"og:url\" content=\"https:\/\/griddb.net\/en\/blog\/sports-analytics\/\" \/>\n<meta property=\"og:site_name\" content=\"GridDB: Open Source Time Series Database for IoT\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/griddbcommunity\/\" \/>\n<meta property=\"article:published_time\" content=\"2025-07-16T07:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Jul-30-2025-12_15_57-PM.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"1536\" \/>\n\t<meta property=\"og:image:height\" content=\"1024\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"author\" content=\"griddb-admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@GridDBCommunity\" \/>\n<meta name=\"twitter:site\" content=\"@GridDBCommunity\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"griddb-admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/griddb.net\/en\/blog\/sports-analytics\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/sports-analytics\/\"},\"author\":{\"name\":\"griddb-admin\",\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233\"},\"headline\":\"Sports Analytics with GridDB\",\"datePublished\":\"2025-07-16T07:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/sports-analytics\/\"},\"wordCount\":1089,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/sports-analytics\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Jul-30-2025-12_15_57-PM.webp\",\"articleSection\":[\"Blog\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/griddb.net\/en\/blog\/sports-analytics\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/griddb.net\/en\/blog\/sports-analytics\/\",\"url\":\"https:\/\/griddb.net\/en\/blog\/sports-analytics\/\",\"name\":\"Sports Analytics with GridDB | GridDB: Open Source Time Series Database for IoT\",\"isPartOf\":{\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/sports-analytics\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/sports-analytics\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Jul-30-2025-12_15_57-PM.webp\",\"datePublished\":\"2025-07-16T07:00:00+00:00\",\"description\":\"Introduction In modern sports, data-driven decision-making has become essential for gaining a competitive edge. Every step, shot, or lap generates a\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/griddb.net\/en\/blog\/sports-analytics\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/griddb.net\/en\/blog\/sports-analytics\/#primaryimage\",\"url\":\"\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Jul-30-2025-12_15_57-PM.webp\",\"contentUrl\":\"\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Jul-30-2025-12_15_57-PM.webp\",\"width\":1536,\"height\":1024},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#website\",\"url\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/\",\"name\":\"GridDB: Open Source Time Series Database for IoT\",\"description\":\"GridDB is an open source time-series database with the performance of NoSQL and convenience of SQL\",\"publisher\":{\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#organization\",\"name\":\"Fixstars\",\"url\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png\",\"contentUrl\":\"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png\",\"width\":200,\"height\":83,\"caption\":\"Fixstars\"},\"image\":{\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/griddbcommunity\/\",\"https:\/\/x.com\/GridDBCommunity\",\"https:\/\/www.linkedin.com\/company\/griddb-by-toshiba\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233\",\"name\":\"griddb-admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g\",\"caption\":\"griddb-admin\"},\"url\":\"https:\/\/griddb.net\/en\/author\/griddb-admin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Sports Analytics with GridDB | GridDB: Open Source Time Series Database for IoT","description":"Introduction In modern sports, data-driven decision-making has become essential for gaining a competitive edge. Every step, shot, or lap generates a","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/griddb.net\/en\/blog\/sports-analytics\/","og_locale":"en_US","og_type":"article","og_title":"Sports Analytics with GridDB | GridDB: Open Source Time Series Database for IoT","og_description":"Introduction In modern sports, data-driven decision-making has become essential for gaining a competitive edge. Every step, shot, or lap generates a","og_url":"https:\/\/griddb.net\/en\/blog\/sports-analytics\/","og_site_name":"GridDB: Open Source Time Series Database for IoT","article_publisher":"https:\/\/www.facebook.com\/griddbcommunity\/","article_published_time":"2025-07-16T07:00:00+00:00","og_image":[{"width":1536,"height":1024,"url":"https:\/\/griddb.net\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Jul-30-2025-12_15_57-PM.webp","type":"image\/webp"}],"author":"griddb-admin","twitter_card":"summary_large_image","twitter_creator":"@GridDBCommunity","twitter_site":"@GridDBCommunity","twitter_misc":{"Written by":"griddb-admin","Est. reading time":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/griddb.net\/en\/blog\/sports-analytics\/#article","isPartOf":{"@id":"https:\/\/griddb.net\/en\/blog\/sports-analytics\/"},"author":{"name":"griddb-admin","@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233"},"headline":"Sports Analytics with GridDB","datePublished":"2025-07-16T07:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/griddb.net\/en\/blog\/sports-analytics\/"},"wordCount":1089,"commentCount":0,"publisher":{"@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#organization"},"image":{"@id":"https:\/\/griddb.net\/en\/blog\/sports-analytics\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Jul-30-2025-12_15_57-PM.webp","articleSection":["Blog"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/griddb.net\/en\/blog\/sports-analytics\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/griddb.net\/en\/blog\/sports-analytics\/","url":"https:\/\/griddb.net\/en\/blog\/sports-analytics\/","name":"Sports Analytics with GridDB | GridDB: Open Source Time Series Database for IoT","isPartOf":{"@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/griddb.net\/en\/blog\/sports-analytics\/#primaryimage"},"image":{"@id":"https:\/\/griddb.net\/en\/blog\/sports-analytics\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Jul-30-2025-12_15_57-PM.webp","datePublished":"2025-07-16T07:00:00+00:00","description":"Introduction In modern sports, data-driven decision-making has become essential for gaining a competitive edge. Every step, shot, or lap generates a","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/griddb.net\/en\/blog\/sports-analytics\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/griddb.net\/en\/blog\/sports-analytics\/#primaryimage","url":"\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Jul-30-2025-12_15_57-PM.webp","contentUrl":"\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Jul-30-2025-12_15_57-PM.webp","width":1536,"height":1024},{"@type":"WebSite","@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#website","url":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/","name":"GridDB: Open Source Time Series Database for IoT","description":"GridDB is an open source time-series database with the performance of NoSQL and convenience of SQL","publisher":{"@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#organization","name":"Fixstars","url":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/logo\/image\/","url":"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png","contentUrl":"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png","width":200,"height":83,"caption":"Fixstars"},"image":{"@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/griddbcommunity\/","https:\/\/x.com\/GridDBCommunity","https:\/\/www.linkedin.com\/company\/griddb-by-toshiba"]},{"@type":"Person","@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233","name":"griddb-admin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g","caption":"griddb-admin"},"url":"https:\/\/griddb.net\/en\/author\/griddb-admin\/"}]}},"_links":{"self":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/posts\/52187","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/comments?post=52187"}],"version-history":[{"count":0,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/posts\/52187\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/media\/52188"}],"wp:attachment":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/media?parent=52187"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/categories?post=52187"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/tags?post=52187"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}