一、MongoDB 計算距離的優勢
優勢 | 說明 |
---|---|
原生地理空間索引 | 支持?2dsphere ?索引,高效處理地理坐標查詢(毫秒級響應)。 |
內置地理計算函數 | 提供?$near 、$geoWithin 、$geoNear ?等操作符,無需手動實現復雜計算。 |
高性能 | 基于B樹索引優化,海量數據下仍能快速返回結果(如億級點位數據)。 |
靈活的數據模型 | 直接存儲GeoJSON格式坐標,支持點、線、多邊形等復雜地理形狀。 |
與Spring生態集成 | 通過Spring Data MongoDB可簡化開發。 |
二、實現步驟(Spring Boot + MongoDB)
1. 添加依賴
略,可參照前面MongoDB的博客。
2.定義地理位置實體
存儲帶有經緯度的文檔(以“商家”為例):
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
import org.springframework.data.mongodb.core.mapping.Document;@Document(collection = "places")
@Data
public class Place {private String id;private String name;@GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE) // 關鍵:創建地理空間索引private GeoJsonPoint location; // 格式: { type: "Point", coordinates: [經度, 緯度] }}
3. 初始化地理空間索引
確保集合已創建?2dsphere
?索引(若未自動創建,可手動執行):
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.index.GeospatialIndex;@PostConstruct
public void initIndex() {mongoTemplate.indexOps(Place.class).ensureIndex(new GeospatialIndex("location"));
}
4. 實現距離查詢
場景1:查詢附近5公里內的商家(按距離排序)
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;public List<Place> findNearbyPlaces(double longitude, double latitude, double maxDistanceKm) {Point userLocation = new Point(longitude, latitude);Distance distance = new Distance(maxDistanceKm, Metrics.KILOMETERS);NearQuery nearQuery = NearQuery.near(userLocation).maxDistance(distance).spherical(true); // 使用球面幾何計算return mongoTemplate.find(new Query(Criteria.where("location").nearSphere(userLocation).maxDistance(distance.getNormalizedValue())),Place.class);
}
場景2:查詢多邊形區域內的點位
import org.springframework.data.geo.Polygon;public List<Place> findWithinPolygon(List<Point> polygonPoints) {return mongoTemplate.find(Query.query(Criteria.where("location").within(new Polygon(polygonPoints))),Place.class);
}
三、MongoDB地理查詢原理解析
-
索引類型
-
2dsphere
:支持球面幾何計算(地球曲率),適合真實地理場景。 -
2d
:平面計算(簡化模型),適用于小范圍地圖(如游戲地圖)。
-
-
距離算法
MongoDB默認使用?Haversine公式?計算球面距離,精度高。 -
性能對比
-
MySQL:需手動計算?
ST_Distance_Sphere
,無專用索引,性能隨數據量下降。 -
MongoDB:利用地理索引,查詢時間穩定在毫秒級。
-
四、注意事項
-
坐標格式標準化
-
始終使用?
[經度, 緯度]
?順序(GeoJSON標準),避免混淆。 -
示例:
new GeoJsonPoint(116.404, 39.915)
(北京天安門)。
-
-
單位一致性
-
MongoDB默認返回距離單位為米,需在業務層統一轉換(如公里/英里)。
-
-
分頁優化
NearQuery.near(userLocation).maxDistance(distance).skip(20) // 跳過前20條.limit(10); // 每頁10條