前言
前面我们介绍了在 SpringBoot 中操作 ElasticSearch,进行单条和批量数据的增删改查,ElasticSearch 还支持对地理图形的操作。
这里我们将介绍使用 SpringBoot 在 ElasticSearch 中对地理图形进行操作。
实现
准备工作
前面我们完成了 ELK 环境的搭建,这里我们会使用 Kibana 来观察我们创建出来的图形,以及对索引数据操作均在 Kibana 的可视化界面中进行
创建索引
命令行创建
在 ElasticSearch 的数据类型中,有两种与地理图形相关:
geo_point
:地理坐标点;geo_shape
:地理图形。
使用如下语句创建索引:
PUT langjialing_index
{
"mappings": {
"properties": {
"geo_point": {
"type": "geo_point"
},
"geo_shape":{
"type": "geo_shape"
}
}
}
}
代码创建
package com.langjialing.helloworld.controlle1;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/**
* @author 郎家岭伯爵
* @time 2024年6月21日16:47:48
*/
@RestController
@RequestMapping("/es4")
@Slf4j
public class EsController4 {
/**
* Elasticsearch客户端
*/
@Autowired
private RestHighLevelClient client;
/**
* 创建复杂结构的索引。
* @param indexName indexName
* @throws IOException IOException
*/
@GetMapping("/createIndex")
public void createIndex(@RequestParam String indexName) throws IOException {
// 创建索引和映射
// 判断索引是否存在
GetIndexRequest getRequest = new GetIndexRequest(indexName);
boolean exists = client.indices().exists(getRequest, RequestOptions.DEFAULT);
if (!exists) {
/**
* -- 创建索引并指定字段映射
* PUT langjialing_index
* {
* "settings": {
* "number_of_replicas": 1, // 将副本数设置为1,一般为 节点数 × 1
* "number_of_shards": 2 // 将分片数设置为2,一般为 节点数 × 2
* },
* "mappings": {
* "properties": {
* "geo_point": {
* "type": "geo_point"
* },
* "geo_json":{
* "type": "geo_shape"
* }
* }
* }
* }
*/
CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
createIndexRequest.settings(Settings
.builder()
.put("index.number_of_shards", 2)
.put("index.number_of_replicas", 1));
String mapping = "{\n" +
" \"properties\": {\n" +
" \"geo_shape\": {\n" +
" \"type\": \"geo_shape\"\n" +
" },\n" +
" \"geo_point\": {\n" +
" \"type\": \"geo_point\"\n" +
" }\n" +
" }\n" +
"}";
createIndexRequest.mapping(mapping, XContentType.JSON);
CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
}
}
}
查看创建出的索引的字段映射:
GET langjialing_index/_mapping
查看创建出的索引的设置:
GET langjialing_index/_settings
Kibana配置图形可视化
-
配置索引:
-
选择索引:
-
选择要展示的索引:
-
选择数据类型:
-
设置图形颜色并保存:
-
刷新展示的数据:
地理图形操作
Point
geo_shape
也可以存储坐标点数据,它的坐标信息由一个一维数组组成。
命令行创建
POST langjialing_index/_doc/10
{
"geo_shape": {
"type": "point",
"coordinates": [ 100, 40 ]
}
}
代码创建
package com.langjialing.helloworld.controlle1;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/**
* @author 郎家岭伯爵
* @time 2024年6月21日16:47:48
*/
@RestController
@RequestMapping("/es4")
@Slf4j
public class EsController4 {
/**
* Elasticsearch客户端
*/
@Autowired
private RestHighLevelClient client;
/**
* 创建Point点
* @param indexName 索引名称
* @param docId 文档ID
* @throws IOException IOException
*/
@GetMapping("/createPoint")
public void createPoint(@RequestParam String indexName, @RequestParam String docId) throws IOException {
String s = "{\n" +
" \"geo_shape\": {\n" +
" \"type\": \"point\",\n" +
" \"coordinates\": [ 100, 40 ]\n" +
" }\n" +
"}";
// 索引文档
IndexRequest indexRequest = new IndexRequest(indexName);
indexRequest.id(docId);
indexRequest.source(s, XContentType.JSON);
client.index(indexRequest, RequestOptions.DEFAULT);
System.out.println("Document indexed successfully.");
}
}
Linestring
Linestring
由一个二维数组组成。
我们将创建如下线段:
命令行创建
POST langjialing_index/_doc/10
{
"geo_shape": {
"type": "LineString",
"coordinates": [[ 100, 40 ], [100, 45]]
}
}
代码创建
package com.langjialing.helloworld.controlle1;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/**
* @author 郎家岭伯爵
* @time 2024年6月21日16:47:48
*/
@RestController
@RequestMapping("/es4")
@Slf4j
public class EsController4 {
/**
* Elasticsearch客户端
*/
@Autowired
private RestHighLevelClient client;
/**
* 创建Point点
* @param indexName 索引名称
* @param docId 文档ID
* @throws IOException IOException
*/
@GetMapping("/createLine")
public void createLine(@RequestParam String indexName, @RequestParam String docId) throws IOException {
String s = "{\n" +
" \"geo_shape\": {\n" +
" \"type\": \"LineString\",\n" +
" \"coordinates\": [[ 100, 40 ], [100, 45]]\n" +
" }\n" +
"}";
// 索引文档
IndexRequest indexRequest = new IndexRequest(indexName);
indexRequest.id(docId);
indexRequest.source(s, XContentType.JSON);
client.index(indexRequest, RequestOptions.DEFAULT);
System.out.println("Document indexed successfully.");
}
}
Polygon
Polygon
的边界信息由一个三维数组组成,可以在多边形中进行挖洞。
接下来我们将在 ElasticSearch 中创建如下 Polygon
图形:
命令行创建
POST langjialing_index/_doc/10
{
"geo_shape": {
"type": "Polygon",
"coordinates":
[
[
[ 100, 40 ],
[ 105, 40 ],
[ 105, 35 ],
[ 100, 35 ],
[ 100, 40 ]
],
[
[ 102, 38 ],
[ 104, 38 ],
[ 104, 36 ],
[ 102, 36 ],
[ 102, 38 ]
]
]
}
}
代码创建
package com.langjialing.helloworld.controlle1;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/**
* @author 郎家岭伯爵
* @time 2024年6月21日16:47:48
*/
@RestController
@RequestMapping("/es4")
@Slf4j
public class EsController4 {
/**
* Elasticsearch客户端
*/
@Autowired
private RestHighLevelClient client;
/**
* 创建Polygon图形
* @param indexName 索引名称
* @param docId 文档ID
* @throws IOException IOException
*/
@GetMapping("/createPolygon")
public void createPolygon(@RequestParam String indexName, @RequestParam String docId) throws IOException {
String s = "{\n" +
" \"geo_shape\": {\n" +
" \"type\": \"Polygon\",\n" +
" \"coordinates\": \n" +
" [\n" +
" [\n" +
" [ 100, 40 ],\n" +
" [ 105, 40 ],\n" +
" [ 105, 35 ],\n" +
" [ 100, 35 ],\n" +
" [ 100, 40 ]\n" +
" ],\n" +
" [\n" +
" [ 102, 38 ],\n" +
" [ 104, 38 ],\n" +
" [ 104, 36 ],\n" +
" [ 102, 36 ],\n" +
" [ 102, 38 ]\n" +
" ]\n" +
" ]\n" +
" }\n" +
"}";
// 索引文档
IndexRequest indexRequest = new IndexRequest(indexName);
indexRequest.id(docId);
indexRequest.source(s, XContentType.JSON);
client.index(indexRequest, RequestOptions.DEFAULT);
System.out.println("Document indexed successfully.");
}
}
MultiPolygon
MutiPolygon
是 ElasticSearch 中最为复杂的图形,它的边界信息由一个四维数组组成,其中有多个挖洞、飞地等部分。
接下来我们将在 ElasticSearch 中创建如下 MultiPolygon
图形:
命令行创建
POST langjialing_index/_doc/10
{
"geo_shape": {
"type": "MultiPolygon",
"coordinates": [
[
[
[ 100, 40 ],
[ 105, 40 ],
[ 105, 35 ],
[ 100, 35 ],
[ 100, 40 ]
],
[
[ 102, 38 ],
[ 104, 38 ],
[ 104, 36 ],
[ 102, 36 ],
[ 102, 38 ]
]
],
[
[
[ 120, 40 ],
[ 123, 40 ],
[ 123, 37 ],
[ 120, 37 ],
[ 120, 40 ]
]
]
]
}
}
代码创建
package com.langjialing.helloworld.controlle1;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/**
* @author 郎家岭伯爵
* @time 2024年6月21日16:47:48
*/
@RestController
@RequestMapping("/es4")
@Slf4j
public class EsController4 {
/**
* Elasticsearch客户端
*/
@Autowired
private RestHighLevelClient client;
/**
* 创建MultiPolygon图形
* @param indexName 索引名称
* @param docId 文档ID
* @throws IOException IOException
*/
@GetMapping("/createMultiPolygon")
public void createMultiPolygon(@RequestParam String indexName, @RequestParam String docId) throws IOException {
// 这里是一个JSON格式的字符串。
String s = "{\n" +
" \"geo_shape\": {\n" +
" \"coordinates\": [\n" +
" [\n" +
" [\n" +
" [\n" +
" 100.0,\n" +
" 40.0\n" +
" ],\n" +
" [\n" +
" 105.0,\n" +
" 40.0\n" +
" ],\n" +
" [\n" +
" 105.0,\n" +
" 35.0\n" +
" ],\n" +
" [\n" +
" 100.0,\n" +
" 35.0\n" +
" ],\n" +
" [\n" +
" 100.0,\n" +
" 40.0\n" +
" ]\n" +
" ],\n" +
" [\n" +
" [\n" +
" 102.0,\n" +
" 38.0\n" +
" ],\n" +
" [\n" +
" 104.0,\n" +
" 38.0\n" +
" ],\n" +
" [\n" +
" 104.0,\n" +
" 36.0\n" +
" ],\n" +
" [\n" +
" 102.0,\n" +
" 36.0\n" +
" ],\n" +
" [\n" +
" 102.0,\n" +
" 38.0\n" +
" ]\n" +
" ]\n" +
" ],\n" +
" [\n" +
" [\n" +
" [\n" +
" 120.0,\n" +
" 40.0\n" +
" ],\n" +
" [\n" +
" 123.0,\n" +
" 40.0\n" +
" ],\n" +
" [\n" +
" 123.0,\n" +
" 37.0\n" +
" ],\n" +
" [\n" +
" 120.0,\n" +
" 37.0\n" +
" ],\n" +
" [\n" +
" 120.0,\n" +
" 40.0\n" +
" ]\n" +
" ]\n" +
" ]\n" +
" ],\n" +
" \"type\": \"MultiPolygon\"\n" +
" }\n" +
"}";
// 索引文档
IndexRequest indexRequest = new IndexRequest(indexName);
indexRequest.id(docId);
indexRequest.source(s, XContentType.JSON);
client.index(indexRequest, RequestOptions.DEFAULT);
System.out.println("Document indexed successfully.");
}
}
总结
SpringBoot 整合 ElasticSearch,操作复杂图形。
以上几种图形的操作,本质是一样的,都是在 ElasticSearch 中对 geo_shape
类型的数据进行的基本操作。