2011-01-28 6 views
6

私は世界のすべての地理的な場所の場所とその関係を含むテーブルを持っています。どの階層モデルを使用しますか?隣接、ネストまたは列挙?

階層を示す例です。あなたは、データが実際に

  • 入れ子集合
  • データは明らかにどちらか変化しない3つのすべての

    • 列挙パス
    • 隣接リストとして格納されていることがわかります。 Ancestors (5.6million行を持つ)大画像geoplanet_placeshttp://tinyurl.com/68q4ndx

      私はその後、別のテーブルと呼ばれている以下は13911.

      表のWOEIDを持っている場所イギリスのブライトンの直接の祖先の一例ですentities。このテーブルには、地理的な場所にマップしたいアイテムが格納されています。私は基本的な情報をいくつか保存していますが、最も重要なのはgeoplanet_placesからの外来キーであるwoeidです。 enter image description here

      最終的にentitiesテーブルには数千のエンティティが含まれます。エンティティを含むすべてのノードの完全なツリーを返すことができるようにしたいと思います。

      地理的な場所に基づいてエンティティのフィルタリングと検索を容易にし、その特定のノードで検出できるエンティティの数を検出できるようにする予定です。

      私は私のentitiesテーブル内の1つのエンティティを持っているのであれば、私はこの

      `地球(1)

      イギリス(1)

      イングランド(1)のようなものを持っているかもしれません

      イーストサセックス(1)

      ブライトンシティ(1)

      ブライトン(1) `

      私はデヴォンに位置している別のエンティティを持っていることを言って、その後、それはのようなものを示すだろうことができます:

      地球(2)

      ユナイテッドKingom(2)

      イングランド(2)

      デボン(1)(1) ...多くの企業がそれぞれの地理的位置の「内部」であるかと言うだろうなど

      (カウント)がライブである必要はありません。毎時間私のオブジェクトを生成してキャッシングすることができます。

      目的は..エンティティを持っている唯一の国を示す出始めるかもしれないインターフェイスを作成できるようにすることです

      Argentina (1021)Chile (291)...United States (32,103)United Kingdom (12,338)

      のようなので、

      次に、ユナイテッドキンドムなどの場所をクリックすると、英国の子孫であるエンティティを持つすべての直接の子ノードが与えられます。

      United Kindgdomには32の郡がありますが、ドリルダウンするとそのうち23門にエンティティが格納されていれば、残りの9桁は表示したくありません。

      このサイトでは、適切に私が実現したい機能を示しています http://www.homeaway.com/vacation-rentals/europe/r5 enter image description here

      あなたは、私がこのようなデータ構造を管理することをお勧めするにはどうすればよいですか?

      私が使用しているもの

      • PHP
      • MySQLの
      • Solrの

      私はドリルダウンが可能な限り迅速であることを計画。私は検索のために一見無くなるAJAXインターフェイスを作成したい。

      また、インデックス作成をお勧めする列を知りたい場合もあります。

    +0

    これは大きな質問です。 –

    答えて

    8

    一般的には、トラブルの原因となる階層内のクエリの3種類があります。

    1. 戻り、全ての祖先
    2. 戻るすべての子孫
    3. 戻り、すべての子ども(即時の子孫が)。

    ここMySQLの異なる方法の性能を示して少しのテーブルです:

    children
         Ancestors Descendants Children  Maintainability InnoDB 
    Adjacency list   Good  Decent  Excellent  Easy   Yes 
    Nested sets (classic) Poor  Excellent Poor/Excellent Very hard  Yes 
    Nested sets (spatial) Excellent Very good Poor/Excellent Very hard  No 
    Materialized path  Excellent Very good Poor/Excellent Hard   Yes 
    

    poor/excellentは、答えはあなたが私は、隣接リストとの混合方法しているかどうかに依存することを意味します。 e。各レコードにparentIDを格納します。(アイテム)

  • 地球/英国/デヴォンの事「をヨーロッパで目的地を」表示する
  • のお子様を表示する

    1. すべての祖先:

      はあなたの仕事のために、あなたはすべての3つのクエリを必要としますすべての子孫が「ヨーロッパの目的地」を表示する(カウント)

    この種の階層はめったに変更されないため(マージン、反乱などの場合のみ)、私はマテリアライズドパスを使用します。

    varchar型のカラムがインデックス、pathと呼ばれ、それを作成し、このような値でそれを埋める:

    番号が正しい順序(ヨーロッパ1、用234に適切な親の主キー、ある
    1:234:6345:45454: 
    

    英国など)

    数字を1から20(または任意の最大ネスティングレベル)に保つには、levelsという表も必要です。

    SELECT pa.* 
    FROM  places p 
    JOIN  levels l 
    ON  SUBSTRING_INDEX(p.path, ':', l.level) <> p.path 
    JOIN  places pa 
    ON  pa.path = CONCAT(SUBSTRING_INDEX(p.path, ':', l.level), ':') 
    WHERE p.id = @id_of_place_in_devon 
    

    その中の場所のすべての子とカウントを選択するには:

    SELECT pc.*, COUNT(pp.id) 
    FROM places p 
    JOIN places pc 
    ON  pc.parentId = p.id 
    JOIN places pp 
    ON  pp.path BETWEEN pc.path AND CONCAT(pc.path, ':') 
         AND pp.id NOT IN 
         (
         SELECT parentId 
         FROM places 
         ) 
    WHERE p.id = @id_of_europe 
    GROUP BY 
         pc.id 
    
  • +0

    あなたはそのような質問にどのように取り組むことができますか?ご覧のとおり、私はparentIDとlft rgtの値を持っています。問題を完全に誤った視点から見ているかどうかはわかりません。たぶん私は一歩後退する必要があります。たとえば、任意のノードの直下の子と(Count)を返すだけです。しかし、このCount値を取得するには、私はまだ難しいクエリを作成する必要があります。問題は、Count値がクエリで計算され、永続化されないということです。 Count値を保存すると、クエリでもこの値を使用する可能性があります。私はちょうど混乱しています。 :) – Layke

    +0

    pp.id/pp.pathを2番目のクエリに含める必要はありますか?そして、すべての道は次のように終わらなければならない: – Layke

    +0

    Laykes:申し訳ありません、GROUP BYを追加するのを忘れました。 'pp'はカテゴリーそのものではない'ヨーロッパ 'の子供のそれぞれの子孫をすべて選択するテーブルです。これは、同じ 'places'テーブルの別名です。 – Quassnoi

    0

    これは私が思いついたのクエリですべての祖先を選択するには

    。それはあなたがクアスノーを提案するものの適応です。

    SELECT pa.*, level, SUBSTRING_INDEX(p.ancestry, '/', l.level), p.* 
    FROM  geoplanet_places p 
    JOIN  levels l 
    ON  SUBSTRING_INDEX(p.ancestry, '/', l.level) <> p.ancestry 
    JOIN  geoplanet_places pa 
    ON  pa.woeid = SUBSTRING_INDEX(SUBSTRING_INDEX(p.ancestry, '/', l.level),'/',-1) 
    WHERE p.woeid = "13911" 
    

    これは、ブライトンのすべての親を返します。

    クエリの問題は、親にパスが返されず、代わりに同じパスを共有していたノードだということでした。

    SELECT  pa.*, GROUP_CONCAT(pa.name ORDER BY pa.lft asc),group_concat(pa.lft ), pa.ancestry 
                  FROM  geo_places p 
                  JOIN  levels l 
                  ON  SUBSTRING_INDEX(CONCAT(p.ancestry, p.woeid,'/'), '/', l.level) <> p.ancestry 
                  JOIN  geo_places pa 
                  ON  pa.woeid = SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(p.ancestry, p.woeid,'/'), '/', l.level),'/',-1) 
                  WHERE p.woeid IN ("12767488","12832668","12844837","131390","131391","12846428","24534461") 
                  GROUP BY p.woeid 
    
    関連する問題