【问题标题】:Hibernate Search and Spatial - Database DesignHibernate 搜索和空间 - 数据库设计
【发布时间】:2014-03-10 13:19:16
【问题描述】:

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

  1. 空间是否可以通过连接正常工作,或者我应该包括 long/lat 在vehicle_listing 中?
  2. 如果我对我的 ManyToOne 关系使用 @IndexEmbedded 并使用 @Indexed zip_code_detail,是否会为整个 zip_code_detail 表建立索引,还是只连接 zip_code_detail 记录?

我正在寻找具有最佳性能的数据库设计,同时最大限度地减少内存消耗并理想地减少数据重复。

使用 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;

【问题讨论】:

  • 你用的是什么数据库?
  • 您能否提供带注释的类以使其更具体。
  • @Hardy,我提供了一个实体示例。我最终只是将 long/lat 移动到我的车辆列表表中,因为我发现 massindexer 正在索引所有 42k zip 记录,而几乎没有那么多车辆。我原本想加入 zipdetail 以防止数据重复。
  • @CodeJunkie 谢谢。我曾希望你会说 SQL,并为你预先写了一个回复。我不是特别精通 MySQL,但我在 SQL 中做了相当多的空间工作。你想让我把它贴出来看看对你有没有帮助?
  • 我肯定对你的观点感兴趣。

标签: hibernate lucene spatial hibernate-search


【解决方案1】:

我提供了一个 SQL 解决方案(我对 MySQL 不太熟悉),但我希望它对您有所帮助 - 即您可以将其逆向工程为类似的解决方案。

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

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

当然,如果您将纬度/经度坐标存储在车辆级别,您会期望看到性能的小幅提升,因为在查询中进行连接不会产生开销,但您随后会必须在车辆级别(而不仅仅是关联)更新纬度/经度,然后将在空间索引上强制执行更多工作(假设您拥有的车辆多于邮政编码),最终我预计会降低性能。我会假设,除非你知道一个你永远不会知道的事实,否则最终你会拥有比邮政编码更多的车辆,因为邮政编码不会经常变化。

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

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;

在超过 2m 条记录和随机搜索距离的点数据库上的 SQL 中,我得到低于 2 秒的响应和超过 1,000 个结果。使用较小的数据库,您将获得更好的时间,而且我的索引适用于多种几何类型,而不仅仅是点。

我在这里根据几个假设来回答:

  1. 您将邮政编码表示为 5 位数字,这意味着您的表格大约有 40,000 条记录。
  2. 您将邮政编码表示为中心点而不是多边形边界?
  3. 假设车辆是静态的(例如,出于查询的目的,位于家庭住址)而不是运动的(这将需要在单独的表中完全包含带有“时间戳”的空间数据)。

希望它在某种程度上有所帮助。

【讨论】:

  • 谢谢乔恩,你回答了我的问题。我目前没有比邮政编码更多的车辆,但这将在明年发生变化。我的印象是索引没有重复?无论与车辆一起存放时有多少车辆使用它,对于给定的经度/纬度是否总是有一个条目?也许我对索引不了解。
  • @CodeJunkie 完全没有问题。这是一个很好的问题,但我很确定每个空间对象都会有自己的条目。点将只有一个条目,它们属于最低级别的网格参考,所以它不是那么大,但同样,如果你不需要,不要复制数据。 :-)
  • 我目前正在使用 aws small,所以我认为暂时我会将它们留在车辆中以保持较低的内存消耗,但是一旦我开始接近 zip 总数,切换它。希望到那时会有更多收入用于更好的硬件 :) 感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-12
  • 2020-04-09
  • 2011-03-10
  • 1970-01-01
相关资源
最近更新 更多