【Elasticsearch】实现气象数据存储与查询系统

🧑 博主简介:CSDN博客专家历代文学网 (PC端可以访问:https://literature.sinhy.com/#/literature?__c=1000,移动端可微信小程序搜索"历代文学 ")总架构师,15年工作经验,精通Java编程高并发设计Springboot和微服务,熟悉LinuxESXI虚拟化以及云原生Docker和K8s,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
技术合作 请加本人wx(注明来自csdn ):foreast_sea


基于 Elasticsearch 的气象数据存储与查询系统:构建气象数据处理的强大引擎

一、引言

在当今科技飞速发展的时代,气象数据的收集、存储与分析对于气象研究、天气预报以及应对气候变化等诸多方面都具有极为关键的意义。气象部门每天都会通过各种先进的观测设备和技术手段,收集海量的气象数据,这些数据涵盖了气温气压湿度风速降水等多个重要的气象要素。

传统的气象数据处理方式在面对如此庞大且复杂的数据量时,逐渐暴露出诸多局限性。数据存储的效率、查询的速度以及分析的深度和广度都难以满足日益增长的气象研究和业务需求。而 Elasticsearch 的出现,为气象数据的管理带来了全新的解决方案。

Elasticsearch 是一个分布式高可用 、实时的搜索与数据分析引擎,它基于 Lucene 构建,具备强大的全文搜索功能和高效的数据存储与检索能力。在气象领域,它能够轻松应对海量气象数据的存储挑战,通过其灵活且可定制的索引结构,使得气象数据可以被快速地组织和索引。气象工作人员可以利用 Elasticsearch 的丰富查询接口,迅速地从海量数据中提取出所需的气象信息,无论是特定时间段内的气温变化趋势,还是某一地区在历史上的极端气象事件记录,都能够在瞬间得到精准的查询结果。这不仅大大提高了气象数据的利用效率,还为气象预报员深入分析气象变化规律提供了有力的工具,从而能够更加准确地预测未来的天气状况,为农业生产航空航天交通运输等众多行业提供可靠的气象服务保障,助力人类更好地适应和应对气候变化带来的各种影响。

我们将深入探讨如何基于 Elasticsearch 构建气象数据存储与查询系统,详细介绍其中所涉及的技术细节、代码实现以及测试方法。

二、Elasticsearch 数据类型在气象数据中的应用

  1. 数值类型
    • 整数类型(如 long、integer 等):在气象数据中,许多数据可以用整数表示。例如,气压值通常在一定范围内,可以使用整数类型来存储。以百帕为单位的气压数据,一般在 900 到 1100 之间,使用 integer 类型就可以很好地容纳。
    • 浮点数类型(如 double、float 等):气温、湿度等数据可能包含小数部分,适合用浮点数类型存储。比如气温数据,可能精确到小数点后一位,像 25.5℃,使用 double 类型能够准确地记录这些数据。
  2. 日期类型(date):气象数据中的观测时间是非常重要的信息。例如,降水数据的记录必然关联着对应的时间点。通过 date 类型,可以方便地存储和处理这些时间信息,便于后续按照时间维度进行数据查询和分析,如查询某一天或某一时间段内的气象数据变化。
  3. 文本类型(keyword、text):对于一些气象站点的名称、地区名称等信息,可以使用 keyword 类型。keyword 类型适合存储结构化的文本数据,在查询时可以进行精确匹配。而对于一些气象现象的描述,如"暴雨""大风"等,如果需要进行全文搜索和相关性分析,则可以使用 text 类型。

三、Elasticsearch 索引结构设计

  1. 索引名称 :为气象数据创建一个专门的索引,例如"meteorological_data_index"。这个索引将作为所有气象数据存储和查询的基础容器。
  2. 映射(Mapping)
    • 对于气温数据字段,定义如下映射:
json 复制代码
{
  "properties": {
    "temperature": {
      "type": "double"
    }
  }
}
  • 气压字段映射:
json 复制代码
{
  "properties": {
    "pressure": {
      "type": "integer"
    }
  }
}
  • 湿度字段映射:
json 复制代码
{
  "properties": {
    "humidity": {
      "type": "double"
    }
  }
}
  • 风速字段映射:
json 复制代码
{
  "properties": {
    "wind_speed": {
      "type": "double"
    }
  }
}
  • 降水字段映射:
json 复制代码
{
  "properties": {
    "precipitation": {
      "type": "double"
    }
  }
}
  • 观测时间字段映射:
json 复制代码
{
  "properties": {
    "observation_time": {
      "type": "date",
      "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
    }
  }
}
  • 气象站点名称字段映射:
json 复制代码
{
  "properties": {
    "station_name": {
      "type": "keyword"
    }
  }
}

四、相关 Maven 依赖

在 Java 项目中使用 Elasticsearch,需要添加以下 Maven 依赖:

xml 复制代码
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.17.9</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.17.9</version>
</dependency>

这里使用的是 Elasticsearch 7.17.9 版本,其中elasticsearch-rest-high-level-client用于与 Elasticsearch 进行高级别的 REST 交互,elasticsearch核心库提供了基础的功能支持。

五、实现步骤

(一)连接到 Elasticsearch

java 复制代码
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;

public class ElasticsearchConnection {
    private static final String HOST = "localhost";
    private static final int PORT = 9200;

    public static RestHighLevelClient getClient() {
        // 创建 HttpHost 对象,指定 Elasticsearch 服务器地址和端口
        HttpHost httpHost = new HttpHost(HOST, PORT, "http");
        // 创建 RestHighLevelClient 对象,用于与 Elasticsearch 进行交互
        return new RestHighLevelClient(RestClient.builder(httpHost));
    }
}

在上述代码中,首先定义了 Elasticsearch 服务器的主机地址和端口。然后通过HttpHost构建了服务器的连接信息,并使用RestClient.builder创建了RestHighLevelClient,这是与 Elasticsearch 进行交互的核心客户端对象。

(二)创建索引

java 复制代码
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;

import java.io.IOException;

public class IndexCreator {
    public static void createMeteorologicalIndex(RestHighLevelClient client) throws IOException {
        // 创建索引请求对象
        CreateIndexRequest request = new CreateIndexRequest("meteorological_data_index");
        // 设置索引的设置,例如分片数量和副本数量
        request.settings(Settings.builder()
               .put("index.number_of_shards", 3)
               .put("index.number_of_replicas", 1));
        // 设置索引的映射,即字段类型等信息
        request.mapping("{\n" +
                "  \"properties\": {\n" +
                "    \"temperature\": {\n" +
                "      \"type\": \"double\"\n" +
                "    },\n" +
                "    \"pressure\": {\n" +
                "      \"type\": \"integer\"\n" +
                "    },\n" +
                "    \"humidity\": {\n" +
                "      \"type\": \"double\"\n" +
                "    },\n" +
                "    \"wind_speed\": {\n" +
                "      \"type\": \"double\"\n" +
                "    },\n" +
                "    \"precipitation\": {\n" +
                "      \"type\": \"double\"\n" +
                "    },\n" +
                "    \"observation_time\": {\n" +
                "      \"type\": \"date\",\n" +
                "      \"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"\n" +
                "    },\n" +
                "    \"station_name\": {\n" +
                "      \"type\": \"keyword\"\n" +
                "    }\n" +
                "  }\n" +
                "}", XContentType.JSON);
        // 执行创建索引操作
        CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
        // 检查索引是否创建成功
        boolean acknowledged = response.isAcknowledged();
        if (acknowledged) {
            System.out.println("气象数据索引创建成功");
        } else {
            System.out.println("气象数据索引创建失败");
        }
    }
}

这段代码首先创建了CreateIndexRequest对象,指定了要创建的索引名称。然后设置了索引的一些基本设置,如分片数和副本数,接着设置了之前设计好的索引映射。最后通过client.indices().create方法执行索引创建操作,并根据返回结果判断索引是否创建成功。

(三)插入气象数据

java 复制代码
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class DataInserter {
    public static void insertMeteorologicalData(RestHighLevelClient client) throws IOException {
        // 创建要插入的数据对象
        Map<String, Object> data = new HashMap<>();
        data.put("temperature", 25.5);
        data.put("pressure", 1010);
        data.put("humidity", 60.0);
        data.put("wind_speed", 3.5);
        data.put("precipitation", 0.0);
        data.put("observation_time", new Date());
        data.put("station_name", "StationA");

        // 创建索引请求对象
        IndexRequest request = new IndexRequest("meteorological_data_index");
        // 设置文档 ID,如果不设置,Elasticsearch 会自动生成
        request.id("1");
        // 设置要插入的数据内容
        request.source(data, XContentType.JSON);
        // 执行插入数据操作
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        // 检查数据是否插入成功
        if (response.status().getStatus() == 201) {
            System.out.println("气象数据插入成功");
        } else {
            System.out.println("气象数据插入失败");
        }
    }
}

这里首先构建了一个Map对象来表示要插入的气象数据,包含了各种气象要素的值以及观测时间和站点名称。然后创建IndexRequest对象,指定索引名称,并设置文档 ID 和数据内容。最后通过client.index方法将数据插入到 Elasticsearch 中,并根据返回状态判断插入是否成功。

(四)查询气象数据

java 复制代码
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class DataSearcher {
    public static List<Map<String, Object>> searchMeteorologicalData(RestHighLevelClient client) throws IOException {
        // 创建搜索请求对象
        SearchRequest request = new SearchRequest("meteorological_data_index");
        // 创建搜索源构建器
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 设置查询条件,这里查询所有数据
        sourceBuilder.query(QueryBuilders.matchAllQuery());
        request.source(sourceBuilder);
        // 执行搜索操作
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 处理搜索结果
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (SearchHit hit : response.getHits().getHits()) {
            resultList.add(hit.getSourceAsMap());
        }
        return resultList;
    }
}

上述代码创建了SearchRequest对象用于指定搜索的索引。然后通过SearchSourceBuilder构建搜索条件,这里使用QueryBuilders.matchAllQuery查询所有数据。执行搜索操作后,遍历搜索结果SearchHit对象,将其源数据(即气象数据)添加到List中并返回。

六、单元测试及预期输出

(一)测试连接到 Elasticsearch

java 复制代码
import org.elasticsearch.client.RestHighLevelClient;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertNotNull;

public class ElasticsearchConnectionTest {
    @Test
    public void testGetClient() {
        // 获取 Elasticsearch 客户端
        RestHighLevelClient client = ElasticsearchConnection.getClient();
        // 断言客户端不为空
        assertNotNull(client);
    }
}

预期输出:测试通过,表明能够成功获取到 Elasticsearch 客户端对象。

(二)测试创建索引

java 复制代码
import org.elasticsearch.client.RestHighLevelClient;
import org.junit.jupiter.api.Test;

import java.io.IOException;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class IndexCreatorTest {
    @Test
    public void testCreateMeteorologicalIndex() throws IOException {
        // 获取 Elasticsearch 客户端
        RestHighLevelClient client = ElasticsearchConnection.getClient();
        // 创建气象数据索引
        IndexCreator.createMeteorologicalIndex(client);
        // 这里可以进一步添加代码来验证索引是否真正创建成功,例如检查索引是否存在等操作
        // 暂时简单地假设创建成功,后续可完善
        assertTrue(true);
    }
}

预期输出:如果索引创建成功,测试通过,控制台输出"气象数据索引创建成功"。如果创建失败,控制台输出"气象数据索引创建失败",并且测试不通过。

(三)测试插入气象数据

java 复制代码
import org.elasticsearch.client.RestHighLevelClient;
import org.junit.jupiter.api.Test;

import java.io.IOException;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class DataInserterTest {
    @Test
    public void testInsertMeteorologicalData() throws IOException {
        // 获取 Elasticsearch 客户端
        RestHighLevelClient client = ElasticsearchConnection.getClient();
        // 插入气象数据
        DataInserter.insertMeteorologicalData(client);
        // 这里可以进一步添加代码来验证数据是否真正插入成功,例如根据插入的文档 ID 进行查询验证等操作
        // 暂时简单地假设插入成功,后续可完善
        assertTrue(true);
    }
}

预期输出:如果数据插入成功,测试通过,控制台输出"气象数据插入成功"。如果插入失败,控制台输出"气象数据插入失败",并且测试不通过。

(四)测试查询气象数据

java 复制代码
import org.elasticsearch.client.RestHighLevelClient;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class DataSearcherTest {
    @Test
    public void testSearchMeteorologicalData() throws IOException {
        // 获取 Elasticsearch 客户端
        RestHighLevelClient client = ElasticsearchConnection.getClient();
        // 查询气象数据
        List<Map<String, Object>> resultList = DataSearcher.searchMeteorologicalData(client);
        // 断言查询结果不为空
        assertFalse(resultList.isEmpty());
    }
}

预期输出:如果查询到数据,测试通过,表明能够成功从 Elasticsearch 中查询到气象数据。如果查询结果为空,测试不通过。

七、参考资料文献

  1. Elasticsearch 官方文档:https://www.elasticsearch.org/guide/index.html
  2. Elasticsearch 实战 》书籍,作者:[美] 拉法尔·库切拉[波] 马雷克·罗戈津斯基
  3. 相关气象数据处理与存储的学术论文和技术报告。
相关推荐
AIGC方案1 小时前
基于Hive + Spark离线数仓大数据实战项目(视频+课件+代码+资料+笔记)
大数据·hive·spark
yin1383 小时前
《可信数据空间 技术架构》技术文件正式发布
大数据·架构
患得患失9495 小时前
【前端】【面试】在 Nuxt.js SSR/SSG 应用开发的 SEO 优化方面,你采取了哪些具体措施来提高页面在搜索引擎中的排名?
前端·javascript·搜索引擎
山登绝顶我为峰 3(^v^)36 小时前
Git 命令
大数据·git·算法·计算机
£菜鸟也有梦6 小时前
Hive进阶之路
大数据·数据仓库·hive·hadoop
结冰架构9 小时前
【AI提示词】成本效益分析师
大数据·人工智能·ai·信息可视化·提示词
蚂蚁数据AntData10 小时前
DB-GPT V0.7.1 版本更新:支持多模态模型、支持 Qwen3 系列,GLM4 系列模型 、支持Oracle数据库等
大数据·数据库·gpt·oracle·架构
代码匠心10 小时前
从零开始学Flink:开启实时计算的魔法之旅
java·大数据·flink
TracyCoder12310 小时前
ElasticSearch深入解析(六):集群核心配置
大数据·elasticsearch·jenkins