2009-10-13 43 views
2

我已經在獅身人面像兩個數據源最近的城市:使用PHP獅身人面像API我已經做搜索25英里範圍內匹配的列表按名稱城市和搜索發現有上市(企業)

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 
    ... 
} 

一個緯度/長度沒有任何問題,但現在我需要加入他們......我想能夠:

a)當通過名稱搜索城市時,只返回內有列表的城市25英里和 b)當我查看一個城市(緯度/長度已知)的結果時,拉出距離它們不到25英里的最近3個城市

有沒有辦法構建一個單一的獅身人面像搜索來完成這兩個查找?

編輯基於下面的評論鏈:

我已經更新了我的城市表,包括類型點的場點,並建立在其上的空間索引:

 
> 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 |   | 
+-------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 

但是,當我嘗試更新數據以創建分列拉/長數據的我得到一個錯誤:

 
> update cities_copy set point = Point(latitude, longitude); 
Cannot get geometry object from data you send to the GEOMETRY field 

是我的語法在這裏下車還是我跑陷入其他問題?

+0

如果你的對象是足夠接近對方爲你能夠使用平面地球模型,您需要將您的緯度和經度轉換爲笛卡爾系統,比如說「UTM」或「普爾科沃」或任何最適合你的國家的投影。至於'UPDATE',這個必須是'MySQL'版本的問題。試試這個:'SET coord = GeomFromText(CONCAT('Point(',latitude,'',longitude,')'))','latitude'和'longitude'轉換成笛卡兒系統。 – Quassnoi 2009-10-13 20:20:41

+0

我沒有將lat/long轉換爲笛卡兒,但這正是我上次用來生成點的查詢,最終結果是我不得不使用LineStringFromWKB/AsBinary的東西。 – 2009-10-13 20:24:07

+0

和城市(點)都包含在美國境內(至少現在)。 – 2009-10-13 20:24:47

回答

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 

,但是請注意,如果您有很多引用,它將不會非常有效IES。

爲了使效率更高,您需要創建一個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 
+0

這個只是用mysql然後,對嗎?我希望在獅身人面像中保持搜索,因爲它快得多(我們有25000個城市)。 – 2009-10-13 13:54:33

+0

你可以在'Sphinx'中建立你的索引,使用'MySQL'作爲數據源。因此,您可以在'Sphinx'中繼續搜索並使用'MySQL'的空間功能。 – Quassnoi 2009-10-13 13:56:52

+0

'順便說一句,你的來源的'類型'是什麼? – Quassnoi 2009-10-13 13:58:36