我已经在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个最近的城市
有没有办法构建单个sphinx搜索来完成这两个查找?
根据以下评论链进行修改:
我已更新我的城市表以包含Point类型的字段点并在其上创建空间索引:
> describe cities_copy; +-------------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+-----------------------+------+-----+---------+----------------+ | id | mediumint(7) unsigned | NO | PRI | NULL | auto_increment | | city_name | varchar(64) | NO | MUL | NULL | | | state_name | varchar(64) | NO | | NULL | | | state_abbr | varchar(8) | NO | | NULL | | | county_name | varchar(64) | NO | | NULL | | | county_id | smallint(3) unsigned | NO | | NULL | | | latitude | float(13,10) | NO | MUL | NULL | | | longitude | float(13,10) | NO | | NULL | | | population | int(8) unsigned | NO | MUL | NULL | | | point | point | NO | MUL | NULL | | +-------------+-----------------------+------+-----+---------+----------------+ > show indexes from cities_copy; +-------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | +-------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ | cities_copy | 0 | PRIMARY | 1 | id | A | 23990 | NULL | NULL | | BTREE | | | cities_copy | 0 | city/state | 1 | city_name | A | NULL | NULL | NULL | | BTREE | | | cities_copy | 0 | city/state | 2 | state_abbr | A | 23990 | NULL | NULL | | BTREE | | | cities_copy | 1 | lat/long | 1 | latitude | A | NULL | NULL | NULL | | BTREE | | | cities_copy | 1 | lat/long | 2 | longitude | A | NULL | NULL | NULL | | BTREE | | | cities_copy | 1 | population | 1 | population | A | NULL | NULL | NULL | | BTREE | | | cities_copy | 1 | point | 1 | point | A | NULL | 32 | NULL | | SPATIAL | | +-------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
但是当我尝试更新数据以创建lat / long数据中的点时,我收到错误:
> update cities_copy set point = Point(latitude, longitude); Cannot get geometry object from data you send to the GEOMETRY field
我的语法是在这里还是我遇到了其他一些问题?
答案 0 :(得分:2)
您需要执行以下操作:
创建一个额外的GEOMETRY
字段,该字段将保留Point(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
但是请注意,如果你有很多城市,它将不会非常有效。
为了提高效率,您需要创建一个tesselation表(将在您的位置附近平铺地球表面),计算切片的接近顺序并与它们连接。
这是一个简单的脚本来演示:
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