Hibernate搜索和空间 - 数据库设计

时间:2014-03-10 13:19:16

标签: hibernate lucene spatial hibernate-search

我希望使用空间来定位给定邮政编码x英里范围内的车辆。我想使用两个表,vehicle_listing和zip_code_detail,其中vehicle_listing与zip_code_detail具有ManyToOne关系。我的地址表由包含long / lat等的整个邮政编码数据库组成。

  1. 空间是否可以通过连接正常工作,还是应该包含long / lat 在vehicle_listing中?
  2. 如果我在ManyToOne关系和@Indexed zip_code_detail上使用@IndexEmbedded,是否会对整个zip_code_detail表建立索引,还是只加入zip_code_detail记录?
  3. 我正在寻找具有最佳性能的数据库设计,同时最大限度地减少内存消耗并理想地减少数据重复。

    使用MySql作为数据库的实体设计。

    @Entity
    public class ZipDetail implements Serializable {
    
        @Id 
        @Column(length = 5)
        private String zip; 
    
        private String city;
    
        @ManyToOne
        @JoinColumn(name = "state_id")
        private State state;
    
        @ManyToOne
        @JoinColumn(name = "county_id")
        private County county;
    
        @NonVisual
        private String areaCodes;
    
        @NonVisual
        private Double latitude;
    
        @NonVisual
        private Double longitude;
    
        private String country;
    

    VehicleListing.class

    @Indexed
    @Spatial(spatialMode = SpatialMode.GRID)
    public class VehicleListing extends BaseEntity {
    
    
        @NonVisual
        @Latitude
        private Double latitude;
    
        @NonVisual
        @Longitude
        private Double longitude;
    
        @IndexedEmbedded
        @ManyToOne
        @JoinColumn(name = "year_id", nullable = false)
        private VehicleYear vehicleYear;
    
        @IndexedEmbedded
        @ManyToOne
        @JoinColumn(name = "make_id", nullable = false)
        private VehicleMake vehicleMake;
    
        @ManyToOne
        @JoinColumn(name = "zip_detail_id", nullable = false)
        private ZipDetail zipDetail;
    

1 个答案:

答案 0 :(得分:1)

我提供了一个SQL解决方案(我不是精通MySQL),但我希望它对你有所帮助 - 也就是说你可以将它逆向工程化为类似的解决方案。

  

空间是否可以通过连接正常工作,还是应该包含long / lat   在vehicle_listing中?

简而言之,是的,它会正常工作。当您加入表时,使用来自两个表的信息的任何查询都将在任一表上使用适当的索引并生成必要的过滤器以保持最大性能 - 无需重复(在任何良好的数据模型中应始终最小化)。

当然,如果您将纬度/经度坐标存储在车辆级别,您可能会看到性能略有改善,因为在您的查询中不会有加入连接的开销,但是你会去必须更新车辆级别的纬度/长度(而不仅仅是关联),然后在空间索引上强制执行更多的工作(假设您的车辆数量超过了邮政编码),这最终会降低性能。我认为,除非你知道一个事实,你永远不会,最终你会有比ZIP代码更多的车辆,因为邮政编码不经常改变。

所以假设以下(对于示例来说是超简化的),我会做这样的事情(这些是在你发布课程之前编写但仍然相关的):

CREATE TABLE [Vehicles]
(
INT [Id],
INT [ZipCodeDetailId] -- Foreign Key on [Zip_Code_Detail].[Id] (Also create Index here)
);

CREATE TABLE [Zip_Code_Detail]
(
INT [Id],
GEOGRAPHY [Location] -- Ensure spatial index on here
);

然后您可以写下以下内容:

DECLARE @searchDistance FLOAT = 1000; -- Distance in metres
DECLARE @searchFrom GEOGRAPHY = GEOGRAPHY::STPointFromText('POINT(12.3456 56.7890)', 4326);

SELECT
COUNT(V.*)
FROM [Vehicles] V
JOIN [Zip_Code_Detail] ZIP ON ZIP.[Id] = V.[ZipCodeDetailId]
WHERE
ZIP.[Location].STDistance(@searchFrom) <= @searchDistance;

在SQL上有超过2米记录和随机搜索距离的点数据库中,我获得了超过1,000个结果的子2s响应。使用较小的数据库可以获得更好的时间,我的索引适用于多种几何类型,而不仅仅是点。

我基于以下几个假设回答:

  1. 您将邮政编码表示为5位数,这意味着您的表格有大约40,000条记录。
  2. 您将邮政编码表示为中心点而非多边形边界?
  3. 假设车辆是静态的(例如在查询目的的家庭地址)而不是运动(这将需要在单独的表格上具有“时间戳”的空间数据)。
  4. 希望它在某种程度上有所帮助。