spark es的新增索引值(地理空间坐标)


一、新建Mapping

可以在Kibana中建好mapping,也可以在api中写好,执行程序的时候创建。
这里在Kibana已经创建好

PUT /realweather
{
    "mappings": {
        "properties": {
            "@timestamp": {
                "type": "date",
				"format": "yyyy-MM-dd HH:mm:ss"
            },
            "realtime": {
                "type": "date",
				"format": "yyyy-MM-dd HH:mm:ss"
            },
            "geometry": {
                "type": "geo_shape"
            },
            "tem": {
                "type": "integer",
               "index": false
            },
            "vis": {
                "type": "double",
               "index": false
            }
        }
    }
}
  • 日期类型设定为“date”,并设定好日期的格式为"yyyy-MM-dd HH:mm:ss"
  • geometry存储的为网格,类型设定为“geo_shape”(polygon),在以坐标或网格检索的时候方便检索
  • “index”: false 意思是该字段不作为索引字段,默认为true

二、导入ES依赖

Java REST Client 有两种风格:

  • Java Low Level REST Client :用于ES的低级客户端。它允许通过http与Elasticsearch集群通信。 将请求编排和响应反编排留给用户自己处理。 它兼容所有的Elasticsearch版本。

  • Java High Level REST Client :用于ES的高级客户端。它提供很多API,并负责请求的编排与响应的反编排。使用需与ES版本保持一致。

就好比是,一个是传自己拼接好的字符串,并且自己解析返回的结果;
而另一个是传对象,返回的结果也已经封装好了直接是对象,更加规范了参数的名称以及格式,更加面向对象
  • 这里使用的是高级API客户端
        <!-- ES -->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.0.0</version>
        </dependency>

三、程序实现

1、创建spark入口、创建ES客户端

  • 因为后续要使用spark ml算法库进行建模训练数据,所以我这里是使用spark程序来实现的,用java也是一样的。
  • 注意地址要写对,端口要使用9200,因为使用的是http
import java.math.BigDecimal
import java.text.SimpleDateFormat

import com.google.gson.JsonObject
import org.apache.http.HttpHost
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
import org.elasticsearch.action.bulk.{BulkRequest, BulkResponse}
import org.elasticsearch.action.index.IndexRequest
import org.elasticsearch.client.{RequestOptions, RestClient, RestHighLevelClient}
import org.elasticsearch.common.settings.Settings
import org.elasticsearch.common.xcontent.{XContentBuilder, XContentFactory, XContentType}

object ParseRealWeather {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf()
      .setAppName(this.getClass.getSimpleName)
      .setMaster("local[*]")
    val sc = new SparkContext(conf)

	// 创建es的客户端
    val client = new RestHighLevelClient(RestClient.builder(new HttpHost("10.xx.xxx.xxx", 9200, "http"), new HttpHost
    ("10.xx.xxx.xxx", 9200, "http")))

2、读取数据,处理前几行头信息

 val lines: RDD[String] = sc.textFile("D:\\testzip\\roadweather\\202008140950.txt")
 
    val startArr: Array[String] = lines.take(5)
    
    val timeStr: String = startArr(0) + "00"
    val format1 = new SimpleDateFormat("yyyyMMddHHmmss")
    val weaTime: Long = format1.parse(timeStr).getTime
    
    val format2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    // 格式化为 mapping中设定的日期格式
    val realTime: String = format2.format(weaTime)
    val latLon: Array[String] = startArr(1).split(" ")
    val latPos: Double = latLon(0).toDouble
    val lonPos: Double = latLon(1).toDouble

3、提取属性值

  • 使用了BigDecimal来解决double类型的值,在做运算时,精度丢失的问题
// 处理的时候过滤掉前几行
    val dataRdd: RDD[String] = lines.filter(!startArr.contains(_))

    dataRdd.take(150).foreach(line => {
      //25_3651:["00029000.00000.00-0.100.119.900801007"]
      val lineArr: Array[String] = line.split(":")

      val tileLat: Int = lineArr(0).split("_")(0).toInt
      val tileLon: Int = lineArr(0).split("_")(1).toInt

	// 解决double类型缺失精度的问题
      val latPosBd = new BigDecimal(latPos.toString())
      val tileLatBd = new BigDecimal((tileLat * 0.01).toString())
      val lonPosBd = new BigDecimal(lonPos.toString())
      val tileLonBd = new BigDecimal((tileLon * 0.01).toString())
      val lat: Double = latPosBd.add(tileLatBd).doubleValue()
      val lon: Double = lonPosBd.add(tileLonBd).doubleValue()

      val tem: Int = lineArr(1).substring(4, 7).toInt
      val vis: Double = lineArr(1).substring(27, 32).toDouble

      val lonBd = new BigDecimal(lon.toString())
      val zzBd = new BigDecimal(0.01.toString())
      val latBd = new BigDecimal(lon.toString())
      val zaBd = new BigDecimal(0.01.toString())
      val finalLon: Double = lonBd.add(zzBd).doubleValue()
      val finalLat: Double = latBd.add(zaBd).doubleValue()

4、将坐标拼成WKT文本

  • 使用的是POLYGON的格式
  • 因为存储的是四边形网格,es中要求网格必须是封闭的,所以网格首尾坐标必须重合
  • 有关WKT的介绍, 请点击这里。
	// 拼接字符串
      val geometry: String = "POLYGON ((" + lat + " " + lon + "," + finalLat + " " + lon + "," + finalLat + "" +
        " " + finalLon + "," + lat + " " + finalLon + "," + lat + " " + lon + "))"

5、将属性拼接成对象

(1) XContentBuilder 形式
      val builder: XContentBuilder = XContentFactory.jsonBuilder()
        .startObject()
        .field("realtime", realTime)
        .field("geometry", geometry)
        .field("tem", tem)
        .field("vis", vis)
        .endObject()

	// 批量处理
      val request = new BulkRequest
      request.add(new IndexRequest("realweather").source(builder))
      val response: BulkResponse = client.bulk(request, RequestOptions.DEFAULT)
    })

(2)Gson的JsonObject 形式
  • 使用gson的JsonObject,在source的时候,需要自己写tostring方法,因为没有toJsonString()方法
    val jsonObject = new JsonObject
          jsonObject.addProperty("realWeaTime", realWeaTime)
    jsonObject.addProperty("geometry", geometry)
    jsonObject.addProperty("tem", tem)
    jsonObject.addProperty("vis", vis)

	// 批量处理
      val request = new BulkRequest
      request.add(new IndexRequest("realweather").source(jsonObject.toString, XContentType.JSON))
      val response: BulkResponse = client.bulk(request, RequestOptions.DEFAULT)
    })
(3)fastJson的JSONObject 形式
  • 使用fastJson的JSONObject,本身有toJsonString()方法,因为source中可以转换
    // 使用fastJson的JSONObject,本身有toJsonString()方法,因为source中可以转换
    val nObject1 = new JSONObject()
    nObject1.put("realWeaTime", realWeaTime)
    nObject1.put("geometry", geometry)
    nObject1.put("tem", tem)
    nObject1.put("vis", vis)

	// 批量处理
      val request = new BulkRequest
      request.add(new IndexRequest("realweather").source(nObject1 ))
      val response: BulkResponse = client.bulk(request, RequestOptions.DEFAULT)
    })
    
注意上面json对象的不同之处,否则在.source()的时候,会报错:The number of object passed must be even but was [1]

6、关闭资源


    client.close()
    sc.stop()
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值