2

我已经在 Sphinx 中有两个数据源:

source cities {
    ...
    sql_query = SELECT id, city_name, state_name, state_abbr, latitude,
                longitude, population FROM cities;
    sql_attr_uint  = population
    sql_attr_float = latitude
    sql_attr_float = longitude
    ...
}

source listings {
    ...
    sql_query = SELECT entry_id, title, url_title, category_names, 
                address1, address2, city, state, zip, latitude, longitude,
                listing_summary, listing_url, extended_info FROM listings;
    sql_attr_float = latitude
    sql_attr_float = longitude
    ...
}

使用 PHP Sphinx API,我已经按名称搜索匹配的城市,并在纬度/经度的 25 英里范围内搜索列表,没有任何问题,但现在我需要“加入”它们......我想成为能够:

a) 按名称搜索城市时,仅返回 25 英里范围内有房源的城市;b) 当我查看一个城市的结果(已知纬度/经度)时,拉出 25 英里范围内有房源的 3 个最近城市其中

有没有办法建立一个单一的狮身人面像搜索来完成这两个查找?

根据下面的评论链进行编辑:

我已经更新了我的城市表以包含一个 Point 类型的字段点并在其上创建了一个空间索引:

> 描述 city_copy;
+-------------+------------+------+---- -+---------+----------------+
| 领域 | 类型 | 空 | 钥匙 | 默认 | 额外 |
+-------------+------------+------+---- -+---------+----------------+
| 编号 | mediumint(7) 无符号 | 否 | 优先级 | 空 | 自动增量 |
| 城市名 | varchar(64) | 否 | 穆尔 | 空 | |
| 州名 | varchar(64) | 否 | | 空 | |
| state_abbr | varchar(8) | 否 | | 空 | |
| 县名 | varchar(64) | 否 | | 空 | |
| 县ID | smallint(3) 无符号 | 否 | | 空 | |
| 纬度 | 浮动(13,10) | 否 | 穆尔 | 空 | |
| 经度 | 浮动(13,10) | 否 | | 空 | |
| 人口 | int(8) 无符号 | 否 | 穆尔 | 空 | |
| 点 | 点 | 否 | 穆尔 | 空 | |
+-------------+------------+------+---- -+---------+----------------+

> 显示来自 city_copy 的索引;
+-------------+------------+------------+--------- -----+-------------+------------+-------------+---- ------+--------+------+------------+---------+
| 表 | 非唯一 | 键名 | Seq_in_index | 列名 | 整理 | 基数| 子部分 | 包装 | 空 | 索引类型 | 评论 |
+-------------+------------+------------+--------- -----+-------------+------------+-------------+---- ------+--------+------+------------+---------+
| city_copy | 0 | 初级 | 1 | 编号 | 一个 | 23990 | 空 | 空 | | BTREE | |
| city_copy | 0 | 城市/州 | 1 | 城市名 | 一个 | 空 | 空 | 空 | | BTREE | |
| city_copy | 0 | 城市/州 | 2 | state_abbr | 一个 | 23990 | 空 | 空 | | BTREE | |
| city_copy | 1 | 纬度/经度 | 1 | 纬度 | 一个 | 空 | 空 | 空 | | BTREE | |
| city_copy | 1 | 纬度/经度 | 2 | 经度 | 一个 | 空 | 空 | 空 | | BTREE | |
| city_copy | 1 | 人口 | 1 | 人口 | 一个 | 空 | 空 | 空 | | BTREE | |
| city_copy | 1 | 点 | 1 | 点 | 一个 | 空 | 32 | 空 | | 空间 | |
+-------------+------------+------------+--------- -----+-------------+------------+-------------+---- ------+--------+------+------------+---------+

但是,当我尝试更新数据以从纬度/经度数据中创建点时,出现错误:

> 更新 city_copy 设置点 = 点(纬度,经度);
无法从您发送到 GEOMETRY 字段的数据中获取几何对象

我的语法是在这里还是我遇到了其他问题?

4

1 回答 1

2

您需要执行以下操作:

  • 创建一个额外的GEOMETRY字段,将Point(Latitude, Longitude)latitude 和 longitude 替换为平坦地球的公制坐标。

  • 在该字段上创建SPATIAL索引

  • 修复第一个查询:

    SELECT  *
    FROM    cities cc
    WHERE   EXISTS
            (
            SELECT  NULL
            FROM    listings cp
            WHERE   MBRContains(LineString(Point(cc.latitude - 25, cc.longitude - 25), Point(cc.latitude + 25, cc.longitude + 25)), cp.Coords)
                    AND GLength(LineString(cc.Coords, cp.Coords)) <= 25
            )
    

要找出最近的三个城市,请发出以下查询:

SELECT  cp.*
FROM    cities cc
CROSS JOIN
        cities cp
WHERE   cc.id = @id
ORDER BY
        GLength(LinePoint(cc.Coords, cp.Coords))
LIMIT 3

,但是请注意,如果您有很多城市,则效率不会很高。

为了提高效率,您需要创建一个镶嵌表(它将在您的位置附近平铺地球表面),计算平铺的邻近顺序并加入它们。

这是一个简单的脚本来演示:

CREATE TABLE t_spatial (id INT NOT NULL PRIMARY KEY, coords Point) ENGINE=MyISAM;

INSERT
INTO    t_spatial
VALUES
(1, Point(0, 0)),
(2, Point(0, 1)),
(3, Point(1, 0)),
(4, Point(1, 1));

SELECT  s1.id, s2.id, GLength(LineString(s1.coords, s2.coords))
FROM    t_spatial s1
CROSS JOIN
        t_spatial s2
于 2009-10-13T13:19:10.253 回答