1.项目地址

https://github.com/GuardFTC/elasticsearch-test.git

2.创建实体类

  1. import lombok.Data;
  2. /**
  3. * @author: 冯铁城 [17615007230@163.com]
  4. * @date: 2022-08-29 09:36:45
  5. * @describe: 省份信息
  6. */
  7. @Data
  8. public class Omission {
  9. /**
  10. * 省份名称
  11. */
  12. private String name;
  13. /**
  14. * 经纬度坐标 精度在前 维度在后
  15. */
  16. private double[] location;
  17. }
  1. import cn.hutool.json.JSONObject;
  2. import lombok.Data;
  3. /**
  4. * @author: 冯铁城 [17615007230@163.com]
  5. * @date: 2022-08-29 10:50:31
  6. * @describe: 图形信息
  7. */
  8. @Data
  9. public class TestShape {
  10. /**
  11. * 名称
  12. */
  13. private String name;
  14. /**
  15. * 图形
  16. */
  17. private JSONObject location;
  18. }

3.地理位置Api

geoBoundingBox

  1. @Test
  2. @SneakyThrows(IOException.class)
  3. void geoBoundingBox() {
  4. //1.以宁夏为左上角,台湾为右下角,可以获取到山东,湖南,湖北的相关信息
  5. SearchResponse<Omission> search = secondaryClient.search(s -> s
  6. .index(GEO_POINT_INDEX_NAME)
  7. .query(q -> q.constantScore(c -> c.filter(f -> f.geoBoundingBox(g -> g
  8. .field("location")
  9. .boundingBox(b -> b.tlbr(t -> t
  10. .topLeft(tl -> tl.latlon(l -> l
  11. .lon(104.17)
  12. .lat(35.14)
  13. ))
  14. .bottomRight(br -> br.latlon(l -> l
  15. .lon(119.18)
  16. .lat(20.45)
  17. ))
  18. ))
  19. )))), Omission.class
  20. );
  21. //2.校验
  22. List<Hit<Omission>> hits = search.hits().hits();
  23. Assert.isTrue(3 == hits.size());
  24. List<Omission> omissions = CollStreamUtil.toList(search.hits().hits(), Hit::source);
  25. List<String> names = CollStreamUtil.toList(omissions, Omission::getName);
  26. Assert.isTrue(names.contains("山东"));
  27. Assert.isTrue(names.contains("湖北"));
  28. Assert.isTrue(names.contains("湖南"));
  29. }

geoDistance

  1. @Test
  2. @SneakyThrows(IOException.class)
  3. void geiDistance() {
  4. //1.以北京为圆心,获取2000km内的省份,理论上应该返回北京,山东,湖北,以及湖南4个省份
  5. SearchResponse<Omission> search = secondaryClient.search(s -> s
  6. .index(GEO_POINT_INDEX_NAME)
  7. .query(q -> q.constantScore(c -> c.filter(f -> f.geoDistance(g -> g
  8. .field("location")
  9. .location(l -> l.latlon(ll -> ll
  10. .lon(116.2)
  11. .lat(39.56)
  12. ))
  13. .distance("2000km")
  14. .distanceType(GeoDistanceType.Arc)
  15. )))), Omission.class
  16. );
  17. //2.校验
  18. Assert.isTrue(4 == search.hits().hits().size());
  19. List<Omission> omissions = CollStreamUtil.toList(search.hits().hits(), Hit::source);
  20. List<String> names = CollStreamUtil.toList(omissions, Omission::getName);
  21. Assert.isTrue(names.contains("北京"));
  22. Assert.isTrue(names.contains("山东"));
  23. Assert.isTrue(names.contains("湖北"));
  24. Assert.isTrue(names.contains("湖南"));
  25. }

sort

  1. @Test
  2. @SneakyThrows(IOException.class)
  3. void sort() {
  4. //1.以北京为圆心,获取2000km内的省份,并按照距离倒序 理论上返回顺序为湖南,湖北,山东,北京
  5. SearchResponse<Omission> search = secondaryClient.search(s -> s
  6. .index(GEO_POINT_INDEX_NAME)
  7. .query(q -> q.constantScore(c -> c.filter(f -> f.geoDistance(g -> g
  8. .field("location")
  9. .location(l -> l.latlon(ll -> ll
  10. .lon(116.2)
  11. .lat(39.56)
  12. ))
  13. .distance("2000km")
  14. ))))
  15. .sort(sort -> sort.geoDistance(g -> g
  16. .field("location")
  17. .location(l -> l.latlon(ll -> ll
  18. .lon(116.2)
  19. .lat(39.56)
  20. ))
  21. .order(SortOrder.Desc)
  22. .unit(DistanceUnit.Kilometers)
  23. )), Omission.class
  24. );
  25. //2.校验
  26. Assert.isTrue(4 == search.hits().hits().size());
  27. Assert.isTrue("湖南".equals(search.hits().hits().get(0).source().getName()));
  28. Assert.isTrue("湖北".equals(search.hits().hits().get(1).source().getName()));
  29. Assert.isTrue("山东".equals(search.hits().hits().get(2).source().getName()));
  30. Assert.isTrue("北京".equals(search.hits().hits().get(3).source().getName()));
  31. }

aggregation-GeoDistance

  1. @Test
  2. @SneakyThrows(IOException.class)
  3. void aggregationGeoDistance() {
  4. //1.统计距离北京(包括北京)0~1000km范围、1000km到2000km范围内的省市数量
  5. SearchResponse<Omission> search = primaryClient.search(s -> s
  6. .index(GEO_POINT_INDEX_NAME)
  7. .aggregations("omissionNumber", a -> a.geoDistance(g -> g
  8. .field("location")
  9. .origin(o -> o.latlon(l -> l
  10. .lon(116.2)
  11. .lat(39.56)
  12. ))
  13. .ranges(
  14. AggregationRange.of(ar -> ar.from("0").to("1000")),
  15. AggregationRange.of(ar -> ar.from("1000").to("2000"))
  16. )
  17. .unit(DistanceUnit.Kilometers)
  18. .distanceType(GeoDistanceType.Plane)
  19. )), Omission.class
  20. );
  21. //2.校验
  22. Aggregate omissionNumber = search.aggregations().get("omissionNumber");
  23. List<RangeBucket> rangeBuckets = omissionNumber.geoDistance().buckets().array();
  24. Assert.isTrue(2 == rangeBuckets.size());
  25. for (RangeBucket rangeBucket : rangeBuckets) {
  26. Assert.isTrue(2 == rangeBucket.docCount());
  27. }
  28. }

aggregation-GeoHashGrid

  1. @Test
  2. @SneakyThrows(IOException.class)
  3. void aggregationGeoHashGrid() {
  4. //1.网格聚合,指定geoHash长度为1
  5. SearchResponse<Omission> search = primaryClient.search(s -> s
  6. .index(GEO_POINT_INDEX_NAME)
  7. .aggregations("geoHashData", a -> a.geohashGrid(g -> g
  8. .field("location")
  9. .precision(p -> p.geohashLength(1))
  10. )), Omission.class
  11. );
  12. //2.校验
  13. Aggregate geoHashData = search.aggregations().get("geoHashData");
  14. List<GeoHashGridBucket> geoHashGridBuckets = geoHashData.geohashGrid().buckets().array();
  15. Assert.isTrue(2 == geoHashGridBuckets.size());
  16. }

aggregation-GeoBounds

  1. @Test
  2. @SneakyThrows(IOException.class)
  3. void aggregationGeoBounds() {
  4. //1.得到一个可以包含所有已存储数据的矩形
  5. SearchResponse<Omission> search = primaryClient.search(s -> s
  6. .index(GEO_POINT_INDEX_NAME)
  7. .aggregations("box", a -> a.geoBounds(g -> g
  8. .field("location")
  9. )), Omission.class
  10. );
  11. //2.校验
  12. Aggregate box = search.aggregations().get("box");
  13. GeoBounds bounds = box.geoBounds().bounds();
  14. Assert.isTrue(bounds.isTlbr());
  15. double topLeftLon = bounds.tlbr().topLeft().latlon().lon();
  16. double topLeftLat = bounds.tlbr().topLeft().latlon().lat();
  17. double bottomRightLon = bounds.tlbr().bottomRight().latlon().lon();
  18. double bottomRightLat = bounds.tlbr().bottomRight().latlon().lat();
  19. Assert.isTrue(86.36999999172986 == topLeftLon);
  20. Assert.isTrue(42.44999995920807 == topLeftLat);
  21. Assert.isTrue(116.19999996386468 == bottomRightLon);
  22. Assert.isTrue(21.79999998304993 == bottomRightLat);
  23. }

geoShape

  1. @Test
  2. @SneakyThrows(IOException.class)
  3. void geoShape() {
  4. //1.创建索引
  5. createIndexAndSaveShape();
  6. //2.查询甘肃黑龙江台湾三角形完全包含的,理论上返回北京点
  7. SearchResponse<TestShape> search = primaryClient.search(s -> s
  8. .index(GEO_SHAPE_INDEX_NAME)
  9. .query(q -> q.geoShape(g -> g
  10. .field("location")
  11. .shape(sh -> sh
  12. .indexedShape(f -> f
  13. .index(GEO_SHAPE_INDEX_NAME)
  14. .id("ghtTriangleShape")
  15. .path("location")
  16. )
  17. .relation(GeoShapeRelation.Within)
  18. )
  19. )), TestShape.class
  20. );
  21. //3.校验
  22. Assert.isTrue(1 == search.hits().hits().size());
  23. }
  24. @SneakyThrows(IOException.class)
  25. void createIndexAndSaveShape() {
  26. //1.判定索引是否存在
  27. boolean exist = primaryClient.indices().exists(e -> e.index(GEO_SHAPE_INDEX_NAME)).value();
  28. //2.不存在创建索引
  29. if (!exist) {
  30. //3.创建索引
  31. CreateIndexResponse createIndexResponse = primaryClient
  32. .indices()
  33. .create(c -> c
  34. .index(GEO_SHAPE_INDEX_NAME)
  35. .mappings(m -> m
  36. .properties("name", p -> p.keyword(k -> k))
  37. .properties("location", p -> p.geoShape(gs -> gs))
  38. .dynamic(DynamicMapping.False)
  39. )
  40. );
  41. //4.校验
  42. Assert.isTrue(Boolean.TRUE.equals(createIndexResponse.acknowledged()));
  43. }
  44. //5.清空数据
  45. DeleteByQueryResponse deleteByQueryResponse = primaryClient.deleteByQuery(d -> d
  46. .index(GEO_SHAPE_INDEX_NAME)
  47. .query(q -> q.matchAll(m -> m))
  48. .refresh(Boolean.TRUE)
  49. );
  50. Assert.isTrue(0 == deleteByQueryResponse.failures().size());
  51. //6.准备数据(北京坐标点、甘肃黑龙江台湾三角形、宁夏新疆西藏三角形)
  52. GeoJsonPoint point = GeoJsonPoint.of(116.20, 39.56);
  53. TestShape beijingShape = new TestShape();
  54. beijingShape.setName("北京点");
  55. beijingShape.setLocation(JSONUtil.parseObj(point.toJson()));
  56. GeoJsonPolygon ghtTriangle = GeoJsonPolygon.of(CollUtil.newArrayList(
  57. new Point(92.13, 32.31),
  58. new Point(125.03, 50.49),
  59. new Point(119.18, 20.45),
  60. new Point(92.13, 32.31)
  61. ));
  62. TestShape ghtTriangleShape = new TestShape();
  63. ghtTriangleShape.setName("甘肃黑龙江台湾三角形");
  64. ghtTriangleShape.setLocation(JSONUtil.parseObj(ghtTriangle.toJson()));
  65. GeoJsonPolygon nxxTriangle = GeoJsonPolygon.of(CollUtil.newArrayList(
  66. new Point(105.49, 38.08),
  67. new Point(96.37, 42.45),
  68. new Point(80.24, 31.29),
  69. new Point(105.49, 38.08)
  70. ));
  71. TestShape nxxTriangleShape = new TestShape();
  72. nxxTriangleShape.setName("宁夏新疆西藏三角形");
  73. nxxTriangleShape.setLocation(JSONUtil.parseObj(nxxTriangle.toJson()));
  74. //7.存入数据
  75. BulkResponse bulk = primaryClient.bulk(b -> b
  76. .index(GEO_SHAPE_INDEX_NAME)
  77. .operations(o -> o.create(c -> c.document(beijingShape).id("beijingShape")))
  78. .operations(o -> o.create(c -> c.document(ghtTriangleShape).id("ghtTriangleShape")))
  79. .operations(o -> o.create(c -> c.document(nxxTriangleShape).id("nxxTriangleShape")))
  80. .refresh(Refresh.True)
  81. );
  82. Assert.isFalse(bulk.errors());
  83. }

4.完成版单元测试

  1. import cn.hutool.core.collection.CollStreamUtil;
  2. import cn.hutool.core.collection.CollUtil;
  3. import cn.hutool.core.lang.Assert;
  4. import cn.hutool.json.JSONUtil;
  5. import co.elastic.clients.elasticsearch.ElasticsearchClient;
  6. import co.elastic.clients.elasticsearch._types.*;
  7. import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
  8. import co.elastic.clients.elasticsearch._types.aggregations.AggregationRange;
  9. import co.elastic.clients.elasticsearch._types.aggregations.GeoHashGridBucket;
  10. import co.elastic.clients.elasticsearch._types.aggregations.RangeBucket;
  11. import co.elastic.clients.elasticsearch._types.mapping.DynamicMapping;
  12. import co.elastic.clients.elasticsearch.core.BulkRequest;
  13. import co.elastic.clients.elasticsearch.core.BulkResponse;
  14. import co.elastic.clients.elasticsearch.core.DeleteByQueryResponse;
  15. import co.elastic.clients.elasticsearch.core.SearchResponse;
  16. import co.elastic.clients.elasticsearch.core.search.Hit;
  17. import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
  18. import com.ftc.elasticsearchtest.entity.Omission;
  19. import com.ftc.elasticsearchtest.entity.TestShape;
  20. import lombok.SneakyThrows;
  21. import org.junit.jupiter.api.BeforeEach;
  22. import org.junit.jupiter.api.Test;
  23. import org.springframework.beans.factory.annotation.Qualifier;
  24. import org.springframework.boot.test.context.SpringBootTest;
  25. import org.springframework.data.elasticsearch.core.geo.GeoJsonPoint;
  26. import org.springframework.data.elasticsearch.core.geo.GeoJsonPolygon;
  27. import org.springframework.data.geo.Point;
  28. import javax.annotation.Resource;
  29. import java.io.IOException;
  30. import java.util.List;
  31. /**
  32. * @author: 冯铁城 [17615007230@163.com]
  33. * @date: 2022-08-29 09:35:30
  34. * @describe: ElasticSearch地理位置API单元测试
  35. */
  36. @SpringBootTest
  37. public class ElasticSearchGeoTest {
  38. @Resource
  39. @Qualifier("primaryElasticsearchClient")
  40. private ElasticsearchClient primaryClient;
  41. @Resource
  42. @Qualifier("secondaryElasticsearchClient")
  43. private ElasticsearchClient secondaryClient;
  44. /**
  45. * geo_point索引名称
  46. */
  47. private static final String GEO_POINT_INDEX_NAME = "omission";
  48. /**
  49. * geo_shape索引名称
  50. */
  51. private static final String GEO_SHAPE_INDEX_NAME = "geo_shape";
  52. /**
  53. * GEO_POINT数据
  54. */
  55. private static final String GEO_POINT_DATA_STR = "[{\"name\":\"北京\",\"location\":[116.2,39.56]},{\"name\":\"山东\",\"location\":[114.19,34.22]},{\"name\":\"湖北\",\"location\":[108.21,29.01]},{\"name\":\"湖南\",\"location\":[108.47,24.38]},{\"name\":\"云南\",\"location\":[97.31,21.8]},{\"name\":\"新疆\",\"location\":[86.37,42.45]}]";
  56. @BeforeEach
  57. @SneakyThrows(IOException.class)
  58. void createIndexAndSaveData() {
  59. //1.判定索引是否存在
  60. boolean exist = primaryClient.indices().exists(e -> e.index(GEO_POINT_INDEX_NAME)).value();
  61. //2.不存在创建索引
  62. if (!exist) {
  63. //3.创建索引
  64. CreateIndexResponse createIndexResponse = primaryClient
  65. .indices()
  66. .create(c -> c
  67. .index(GEO_POINT_INDEX_NAME + "_1")
  68. .aliases(GEO_POINT_INDEX_NAME, a -> a)
  69. .mappings(m -> m
  70. .properties("name", p -> p.keyword(k -> k))
  71. .properties("location", p -> p.geoPoint(g -> g))
  72. )
  73. .settings(s -> s
  74. .refreshInterval(r -> r.time("1s"))
  75. .numberOfShards("3")
  76. .numberOfReplicas("1")
  77. )
  78. );
  79. //4.校验是否异常
  80. Assert.isTrue(Boolean.TRUE.equals(createIndexResponse.acknowledged()));
  81. }
  82. //5.清空数据
  83. DeleteByQueryResponse deleteByQueryResponse = primaryClient.deleteByQuery(d -> d
  84. .index(GEO_POINT_INDEX_NAME)
  85. .query(q -> q.matchAll(m -> m))
  86. .refresh(Boolean.TRUE)
  87. );
  88. Assert.isTrue(0 == deleteByQueryResponse.failures().size());
  89. //6.构建新增数据
  90. List<Omission> omissions = JSONUtil.toList(GEO_POINT_DATA_STR, Omission.class);
  91. BulkRequest.Builder builder = new BulkRequest.Builder();
  92. builder.index(GEO_POINT_INDEX_NAME);
  93. omissions.forEach(om -> builder.operations(o -> o.create(c -> c.document(om))));
  94. builder.refresh(Refresh.True);
  95. //7.新增数据
  96. BulkResponse bulk = primaryClient.bulk(builder.build());
  97. Assert.isFalse(bulk.errors());
  98. }
  99. @Test
  100. @SneakyThrows(IOException.class)
  101. void geoBoundingBox() {
  102. //1.以宁夏为左上角,台湾为右下角,可以获取到山东,湖南,湖北的相关信息
  103. SearchResponse<Omission> search = secondaryClient.search(s -> s
  104. .index(GEO_POINT_INDEX_NAME)
  105. .query(q -> q.constantScore(c -> c.filter(f -> f.geoBoundingBox(g -> g
  106. .field("location")
  107. .boundingBox(b -> b.tlbr(t -> t
  108. .topLeft(tl -> tl.latlon(l -> l
  109. .lon(104.17)
  110. .lat(35.14)
  111. ))
  112. .bottomRight(br -> br.latlon(l -> l
  113. .lon(119.18)
  114. .lat(20.45)
  115. ))
  116. ))
  117. )))), Omission.class
  118. );
  119. //2.校验
  120. List<Hit<Omission>> hits = search.hits().hits();
  121. Assert.isTrue(3 == hits.size());
  122. List<Omission> omissions = CollStreamUtil.toList(search.hits().hits(), Hit::source);
  123. List<String> names = CollStreamUtil.toList(omissions, Omission::getName);
  124. Assert.isTrue(names.contains("山东"));
  125. Assert.isTrue(names.contains("湖北"));
  126. Assert.isTrue(names.contains("湖南"));
  127. }
  128. @Test
  129. @SneakyThrows(IOException.class)
  130. void geoDistance() {
  131. //1.以北京为圆心,获取2000km内的省份,理论上应该返回北京,山东,湖北,以及湖南4个省份
  132. SearchResponse<Omission> search = secondaryClient.search(s -> s
  133. .index(GEO_POINT_INDEX_NAME)
  134. .query(q -> q.constantScore(c -> c.filter(f -> f.geoDistance(g -> g
  135. .field("location")
  136. .location(l -> l.latlon(ll -> ll
  137. .lon(116.2)
  138. .lat(39.56)
  139. ))
  140. .distance("2000km")
  141. .distanceType(GeoDistanceType.Arc)
  142. )))), Omission.class
  143. );
  144. //2.校验
  145. Assert.isTrue(4 == search.hits().hits().size());
  146. List<Omission> omissions = CollStreamUtil.toList(search.hits().hits(), Hit::source);
  147. List<String> names = CollStreamUtil.toList(omissions, Omission::getName);
  148. Assert.isTrue(names.contains("北京"));
  149. Assert.isTrue(names.contains("山东"));
  150. Assert.isTrue(names.contains("湖北"));
  151. Assert.isTrue(names.contains("湖南"));
  152. }
  153. @Test
  154. @SneakyThrows(IOException.class)
  155. void sort() {
  156. //1.以北京为圆心,获取2000km内的省份,并按照距离倒序 理论上返回顺序为湖南,湖北,山东,北京
  157. SearchResponse<Omission> search = secondaryClient.search(s -> s
  158. .index(GEO_POINT_INDEX_NAME)
  159. .query(q -> q.constantScore(c -> c.filter(f -> f.geoDistance(g -> g
  160. .field("location")
  161. .location(l -> l.latlon(ll -> ll
  162. .lon(116.2)
  163. .lat(39.56)
  164. ))
  165. .distance("2000km")
  166. ))))
  167. .sort(sort -> sort.geoDistance(g -> g
  168. .field("location")
  169. .location(l -> l.latlon(ll -> ll
  170. .lon(116.2)
  171. .lat(39.56)
  172. ))
  173. .order(SortOrder.Desc)
  174. .unit(DistanceUnit.Kilometers)
  175. )), Omission.class
  176. );
  177. //2.校验
  178. Assert.isTrue(4 == search.hits().hits().size());
  179. Assert.isTrue("湖南".equals(search.hits().hits().get(0).source().getName()));
  180. Assert.isTrue("湖北".equals(search.hits().hits().get(1).source().getName()));
  181. Assert.isTrue("山东".equals(search.hits().hits().get(2).source().getName()));
  182. Assert.isTrue("北京".equals(search.hits().hits().get(3).source().getName()));
  183. }
  184. @Test
  185. @SneakyThrows(IOException.class)
  186. void aggregationGeoDistance() {
  187. //1.统计距离北京(包括北京)0~1000km范围、1000km到2000km范围内的省市数量
  188. SearchResponse<Omission> search = primaryClient.search(s -> s
  189. .index(GEO_POINT_INDEX_NAME)
  190. .aggregations("omissionNumber", a -> a.geoDistance(g -> g
  191. .field("location")
  192. .origin(o -> o.latlon(l -> l
  193. .lon(116.2)
  194. .lat(39.56)
  195. ))
  196. .ranges(
  197. AggregationRange.of(ar -> ar.from("0").to("1000")),
  198. AggregationRange.of(ar -> ar.from("1000").to("2000"))
  199. )
  200. .unit(DistanceUnit.Kilometers)
  201. .distanceType(GeoDistanceType.Plane)
  202. )), Omission.class
  203. );
  204. //2.校验
  205. Aggregate omissionNumber = search.aggregations().get("omissionNumber");
  206. List<RangeBucket> rangeBuckets = omissionNumber.geoDistance().buckets().array();
  207. Assert.isTrue(2 == rangeBuckets.size());
  208. for (RangeBucket rangeBucket : rangeBuckets) {
  209. Assert.isTrue(2 == rangeBucket.docCount());
  210. }
  211. }
  212. @Test
  213. @SneakyThrows(IOException.class)
  214. void aggregationGeoHashGrid() {
  215. //1.网格聚合,指定geoHash长度为1
  216. SearchResponse<Omission> search = primaryClient.search(s -> s
  217. .index(GEO_POINT_INDEX_NAME)
  218. .aggregations("geoHashData", a -> a.geohashGrid(g -> g
  219. .field("location")
  220. .precision(p -> p.geohashLength(1))
  221. )), Omission.class
  222. );
  223. //2.校验
  224. Aggregate geoHashData = search.aggregations().get("geoHashData");
  225. List<GeoHashGridBucket> geoHashGridBuckets = geoHashData.geohashGrid().buckets().array();
  226. Assert.isTrue(2 == geoHashGridBuckets.size());
  227. }
  228. @Test
  229. @SneakyThrows(IOException.class)
  230. void aggregationGeoBounds() {
  231. //1.得到一个可以包含所有已存储数据的矩形
  232. SearchResponse<Omission> search = primaryClient.search(s -> s
  233. .index(GEO_POINT_INDEX_NAME)
  234. .aggregations("box", a -> a.geoBounds(g -> g
  235. .field("location")
  236. )), Omission.class
  237. );
  238. //2.校验
  239. Aggregate box = search.aggregations().get("box");
  240. GeoBounds bounds = box.geoBounds().bounds();
  241. Assert.isTrue(bounds.isTlbr());
  242. double topLeftLon = bounds.tlbr().topLeft().latlon().lon();
  243. double topLeftLat = bounds.tlbr().topLeft().latlon().lat();
  244. double bottomRightLon = bounds.tlbr().bottomRight().latlon().lon();
  245. double bottomRightLat = bounds.tlbr().bottomRight().latlon().lat();
  246. Assert.isTrue(86.36999999172986 == topLeftLon);
  247. Assert.isTrue(42.44999995920807 == topLeftLat);
  248. Assert.isTrue(116.19999996386468 == bottomRightLon);
  249. Assert.isTrue(21.79999998304993 == bottomRightLat);
  250. }
  251. @Test
  252. @SneakyThrows(IOException.class)
  253. void geoShape() {
  254. //1.创建索引
  255. createIndexAndSaveShape();
  256. //2.查询甘肃黑龙江台湾三角形完全包含的,理论上返回北京点
  257. SearchResponse<TestShape> search = primaryClient.search(s -> s
  258. .index(GEO_SHAPE_INDEX_NAME)
  259. .query(q -> q.geoShape(g -> g
  260. .field("location")
  261. .shape(sh -> sh
  262. .indexedShape(f -> f
  263. .index(GEO_SHAPE_INDEX_NAME)
  264. .id("ghtTriangleShape")
  265. .path("location")
  266. )
  267. .relation(GeoShapeRelation.Within)
  268. )
  269. )), TestShape.class
  270. );
  271. //3.校验
  272. Assert.isTrue(1 == search.hits().hits().size());
  273. }
  274. @SneakyThrows(IOException.class)
  275. void createIndexAndSaveShape() {
  276. //1.判定索引是否存在
  277. boolean exist = primaryClient.indices().exists(e -> e.index(GEO_SHAPE_INDEX_NAME)).value();
  278. //2.不存在创建索引
  279. if (!exist) {
  280. //3.创建索引
  281. CreateIndexResponse createIndexResponse = primaryClient
  282. .indices()
  283. .create(c -> c
  284. .index(GEO_SHAPE_INDEX_NAME)
  285. .mappings(m -> m
  286. .properties("name", p -> p.keyword(k -> k))
  287. .properties("location", p -> p.geoShape(gs -> gs))
  288. .dynamic(DynamicMapping.False)
  289. )
  290. );
  291. //4.校验
  292. Assert.isTrue(Boolean.TRUE.equals(createIndexResponse.acknowledged()));
  293. }
  294. //5.清空数据
  295. DeleteByQueryResponse deleteByQueryResponse = primaryClient.deleteByQuery(d -> d
  296. .index(GEO_SHAPE_INDEX_NAME)
  297. .query(q -> q.matchAll(m -> m))
  298. .refresh(Boolean.TRUE)
  299. );
  300. Assert.isTrue(0 == deleteByQueryResponse.failures().size());
  301. //6.准备数据(北京坐标点、甘肃黑龙江台湾三角形、宁夏新疆西藏三角形)
  302. GeoJsonPoint point = GeoJsonPoint.of(116.20, 39.56);
  303. TestShape beijingShape = new TestShape();
  304. beijingShape.setName("北京点");
  305. beijingShape.setLocation(JSONUtil.parseObj(point.toJson()));
  306. GeoJsonPolygon ghtTriangle = GeoJsonPolygon.of(CollUtil.newArrayList(
  307. new Point(92.13, 32.31),
  308. new Point(125.03, 50.49),
  309. new Point(119.18, 20.45),
  310. new Point(92.13, 32.31)
  311. ));
  312. TestShape ghtTriangleShape = new TestShape();
  313. ghtTriangleShape.setName("甘肃黑龙江台湾三角形");
  314. ghtTriangleShape.setLocation(JSONUtil.parseObj(ghtTriangle.toJson()));
  315. GeoJsonPolygon nxxTriangle = GeoJsonPolygon.of(CollUtil.newArrayList(
  316. new Point(105.49, 38.08),
  317. new Point(96.37, 42.45),
  318. new Point(80.24, 31.29),
  319. new Point(105.49, 38.08)
  320. ));
  321. TestShape nxxTriangleShape = new TestShape();
  322. nxxTriangleShape.setName("宁夏新疆西藏三角形");
  323. nxxTriangleShape.setLocation(JSONUtil.parseObj(nxxTriangle.toJson()));
  324. //7.存入数据
  325. BulkResponse bulk = primaryClient.bulk(b -> b
  326. .index(GEO_SHAPE_INDEX_NAME)
  327. .operations(o -> o.create(c -> c.document(beijingShape).id("beijingShape")))
  328. .operations(o -> o.create(c -> c.document(ghtTriangleShape).id("ghtTriangleShape")))
  329. .operations(o -> o.create(c -> c.document(nxxTriangleShape).id("nxxTriangleShape")))
  330. .refresh(Refresh.True)
  331. );
  332. Assert.isFalse(bulk.errors());
  333. }
  334. }