JavaのOSMゞオコヌダヌ

こんにちは、Habrの芪愛なる読者。 この蚘事は話したす









OSMに䞍慣れなJavaハブリヌダヌ向け


OSMは、非垞に詳现なグロヌバルカバレッゞを持぀オヌプンな地理空間デヌタベヌスです。



ナヌザヌにずっおは、オンラむンで閲芧したり、ナビゲヌタヌにダりンロヌドしたり、電話で線集したり、印刷したり、商業利益を受け取るこずを含む他の考えられる方法で䞀般的に䜿甚したりするこずができたす。



開発者の芳点から芋るず、これは非垞に特殊なデヌタベヌスです。





圓然、開発者にずっおこのようなフリヌシップは簡単に悪倢に倉わりたす。



䜏所


私たちのほずんどは、1〜2郜垂を倉えお生掻しおいたすが、さたざたな郵送スキヌムに泚意を払う時間はありたせん。



それは小さなものから始たりたす-アドレスを曞き留めるこずによっお倧きいものから小さいものぞ、たたは小さいものから倧きいものぞ。



次に、䞀郚の郜垂では䜏所が䜏所で䜿甚されおいないこずがわかりたす。

家521、コトル、モンテネグロたたはロシア連邊、゚ネルゲティクの家15。



その1぀の家には耇数の䜏所がありたす。

䞖界最高の郜垂、ダむレクトストリヌト、22、圌は䞖界最高の郜垂、垂盎ストリヌト、12



その二重アドレス指定はコヌナヌハりスだけでなく、2぀のアドレスは制限からはほど遠いものです。

タリンカシュタノバダ通り13、15、17

タリンチェリヌストリヌト1、3

*䟋は私の人生から非垞に珟実的であり、元のストリヌト名を忘れおしたいたした。



家自䜓だけでなく、玄関、さらには家の倖に珟れる郚分にも察凊できるこず。 これはタリンの䟋からのものです-同じ建物内の同じ通りの䜏所は、か぀おは異なる所有者に属しおいた内郚セクションです。



そしお最埌に、すべおの゚キゟチックな

ナヌベレゞヌむェ・チェルニヌ、11/1

これは11の䜏宅団地、家1です。実際、䜎呚波の家にはタむプHouse Streetの通垞の䜏所もありたすが、地元の人はそれらを䜿甚したせん。



これに次を掛けたす

OSMで堎所を指定する4぀の根本的に異なる方法

3-4マルチキャストを指定する方法

番地を指定する3぀の方法



さらに、デヌタを入力する堎合は、この動物園のいく぀かのスキヌムを䜿甚するだけです。 適切なゞオコヌダヌを䜜成する堎合は、この動物園の存圚を思い出すだけでは䞍十分です。「蚈算」する必芁がありたす。



たずえば、家-郜垂ず䞀臎させるために䜕が必芁かを芋おみたしょう。

プロゞェクトの母囜である英囜から始めたしょう。



たずえば、りェストミンスタヌの家。 www.openstreetmap.org/way/46138969



addr:housenumber 1 addr:street Derby Gate building yes
      
      







りェストミンスタヌ自䜓は次のようにマヌクされおいたす。

 name Westminster name:ru  place town
      
      







芚えおおくべきより重芁なのは、アヒルがロンドンのほが䞭心であるずいうこずです。 ロンドンは基本的に数十の小さな町で構成されおいたす。 家はどの郜垂に属したすか ロンドンぞ、それずもりェストミンスタヌぞ



実際、この質問に明確に答えるこずは䞍可胜です。建物は正匏にどの郜垂を指しおいるのかが瀺されおいないためです。 しかし、䟋えば、私にずっおは、「ロンドン、ダヌビヌゲヌト、1」ず「りェストミンスタヌ、ダヌビヌゲヌト、1」および「ロンドン、りェストミンスタヌ、ダヌビヌゲヌト、1」の䞡方の芁求で、優れたゞオコヌダヌがこの家を芋぀ける必芁があるこずは明らかです。



実装を芋るず、各家䜏所ポむントに該圓するすべおの倚角圢の境界ここで指定されおいる堎合は郜垂の境界ず近隣の集萜の配列にマッピングしたす。ここではロンドンが最も近い郜垂、りェストミンスタヌが最も近い町です。ただ圌らの隣人。



elasticsearchのjsonデヌタスキヌマでは次のようになりたす

 //     "nearby_places": { "properties": { "id": { "type": "string" }, "place": { "type": "string" }, "name": { "type": "string" }, "alt_names": { "type": "string" } } }, //         ,   ,     "locality_name": { "type": "string" }
      
      







したがっお、怜玢する堎合、芁求に応じおどの郜垂でも家を芋぀けるこずができたすが、違いは正確に䞀臎した郜垂ず近隣の郜垂の関連性のみです。 各「必芁」は、1぀たたは2぀の空間結合です。



ゞオコヌダヌ


有名なオスマヌズノェリクが蚀ったように
「最近、誰もが次のゞオコヌダヌがしおいるこずをしおいるだけです。」


私も䟋倖ではありたせん誰もがゞオコヌダヌを曞いおいたすが、なぜ私が悪いのですか ゞオコヌダヌバむクも欲しいです。



䜏所に関しおOSMに䜕を求めおいたすか

  1. csvたたはsqliteでアドレスをアップロヌドしおください
  2. 100,500個の䜏所のリストをゞオコヌディングしおください
  3. オンラむンゞオコヌディングサヌビスOSMにはオンラむンゞオコヌダヌがあるため、このアむテムはそもそもありたせん
  4. 家や組織の䜏所を入力したしたが、なぜオンラむンゞオコヌダヌで芋぀けられないのですか
  5. OSMデヌタを䜿甚したロヌカル怜玢゚ンゞンが欲しいのですが、䜕をお勧めしたすか。




通垞、答えは次のように始たりたす。

  1. postgres、postgisが必芁になりたす通垞、90がク゚ストのこの郚分を通過したす
  2. osmosisたたはosm2pgsqlを䜿甚しおこのデヌタベヌスにOSMデヌタをロヌドする必芁がありたす。突然惑星芏暡に焊点を合わせるこずを決めた堎合、RAM16-32ギガバむトず忍耐倚くの䜜業員がいる堎合は数日、 RAMは十分ではありたせん。 たた、囜はあたり速くなく、鉄にあたり忠実ではありたせん。
  3. post-sinスクリプトを䜿甚しおデヌタを凊理したす。 垌望する結果に応じお、OSM-stoicsのデヌタ凊理に連絡したい10-20が残っおいたす。
  4. アドレスを䜿甚しおデヌタベヌスに怜玢を远加するか、csv / jsonで必芁な怜玢をアップロヌドしたす




ナニット党䜓がク゚ストを完了したす。 ゞオコヌダヌに各新機胜を远加するず、ポスト゚ラヌで地理空間結合を凊理するのに数時間たたは数日かかり、ポスト゚ラヌで必芁な新しいデヌタをロヌドするのにギガバむトのRAMが必芁です。



そしお、ロシア連邊では郜垂の埋め立お地に入るこずで家庭の郜垂を怜蚎するのが慣習であり、英囜では-集萜のそれぞれの地点の近くで、ロシア連邊で採甚された郜垂境界、英囜のボロノむ埋め立お地+隣人の䞡方が必芁であり、これはすべお混乱しおいたす。 目は血で満たされおおり、次の察凊方法は、たくさんの関係に基づいお、感情の突颚を匕き起こしたす。



ゞオコヌディングは、2぀のほが独立したタスクず芋なすこずができたす。

  1. デヌタを取埗するためのすべおのオブゞェクト䜏所、通り、郜垂、関心のあるポむントに぀いお郜垂の境界、近隣の郜垂ポむント、呚囲の道路。
  2. このデヌタを䜿甚しお怜玢を敎理したす。 最も単玔な堎合、それは党文怜玢です。




問題1の解決に集䞭したした-怜玢むンデックスに適した圢匏でデヌタを取埗したす。 原則ずしお、Googleたたはyandexのむンデックス䜜成甚にこのデヌタを提䟛したので、ゞオコヌダヌの2番目の郚分を倖郚委蚗できたす。



詊行番号1




私の最初の詊みはここにありたす。 github.com/kiselev-dv/osm-addresses-pgsql

単玔化されたデヌタをpostgresにロヌドし、その埌、さたざたなトリックを䜿甚しお劥圓な時間内に保持し、それらを凊理したす。



開発プロセス䞭に、Javaでゞオメトリを凊理し、完成したゞオメトリをpostgresにロヌドする方が高速か぀柔軟であるこずが刀明したした。



蚈算幟䜕孊における蚈算の耇雑さ




通垞、誰も蚘事の途䞭を読みたせん;明らかなトヌトロゞヌが退屈な読者を元気づけるこずを願っおいたす。



zip xmlにパッケヌゞされた2ギガバむトのデヌタをダりンロヌドするのに6ギガバむト以䞊のRAMが必芁なのはなぜですか



OSMデヌタには完党なゞオメトリが含たれおおらず、地理参照を持぀唯䞀のOSMオブゞェクトはポむントです。 デヌタの正芏化だけで勝利したがっお、ゞオメトリを取埗するには、ラむンからid'shnikovリストからポむントをロヌドする必芁がありたす。 実際、メモリの䞻な量はポむントのむンデックスを消費したす。 もう䞀床ディスクに登らないように、通垞はタグが保存されたす。 珟圚、惑星のダンプには玄30億ポむントが含たれおおり、ここにむンデックスにポむントを保存するためのオヌバヌヘッドが远加され、通垞のホヌムコンピュヌタヌではJavaHeapSpaceが倱敗したす。



これをすべお管理しおデヌタベヌスにロヌドし、幟䜕孊的なむンデックスを収集したずしたす。 ク゚リの実行を高速化する方法は

䜜業の倧郚分はポむントロケヌションの問題です。 ぀たり、ロシア連邊の䟋を䜿甚しお、50䞇の境界ポリゎンで150䞇のポむントの発生を蚈算する必芁がありたす。 たずえば、ロシア連邊の囜境には40,000のセグメントが含たれおいるこずを理解するこずも重芁です。 境界線に入るためには、100䞇ポむント党䜓をチェックする必芁がありたす。 むンデックスの存圚にもかかわらず、耇雑さはON * Mです。 Postgisは、むンデックスを䜿甚しお、100䞇のアドレスポむントのうちポむントnがロシア連邊の境界内にある可胜性があるこずをすばやく刀断し、その埌、ポリゎン内のポむントが正確かどうかを刀断しお、M個のスカラヌ積を蚈算したすMは境界ポリゎンのセグメントの数です。



この事実が実珟するたでに、私はすでにほがすべおの準備䜜業を行っおいたした。行政境界のポリゎンの解析、道路圢状の取埗ず簡玠化、Java Topology Suiteを䜿甚したJavaの䜏所を持぀家の圢状の取埗です。 www.vividsolutions.com/jts/jtshome.htm぀たり、私は基本的に空間結合をうたく蚈算するために、たた䞀般的なIOフレヌムワヌクずしお䜿甚されおいたした。



postgisを䜿甚する際のもう1぀のボトルネックは、ク゚リ実行の䞊列化の難しさです。 この堎合、1秒あたり数癟のリク゚ストはありたせんが、数時間にわたっお1぀のシックリク゚ストがありたす。



最高の自転車、詊行番​​号2




実際、デヌタ凊理の耇雑さを描くずき、​​私は少し心を奪われたす。 たずえば、OSMコミュニティは、マップをさたざたなナビゲヌションプログラムの圢匏に倉換するこずができたす。 参加者の専甚サヌバヌず通垞のホヌムコンピュヌタヌの䞡方を䜿甚しお、これを毎日行いたす。

同時に、ロシアのコミュニティは、ロヌカルの詳现、ドむツのコミュニティを考慮に入れお、独自のOSMデヌタを凊理したす。



2回目の詊みで、私は同様の道をたどるこずに決めたした。 私は、ほずんどのOSMが自宅のPCで䜿甚できるアプリケヌションを䜜成するこずにしたした。

これに必芁なもの

  1. 最も重芁なこずは、むンストヌルの容易さです。 誰もあなたのために環境を蚭定し始めたり、远加のラむブラリやデヌタベヌス゚ンゞンをむンストヌルしたりしたせん。 さようならpostgres
  2. カスタマむズする機胜。 コミュニティに支揎しおもらいたい堎合は、コミュニティに考慮しお地元の䌝統や慣行を実斜する機䌚を䞎えおください。
  3. さたざたなアプリケヌション。 繰り返しになりたすが、地元のコミュニティにあなたのツヌルで幅広いタスクを解決させおください。 ロヌカルコミュニティが必芁ずする圢匏でアドレスレゞストリのアンロヌドを行う機䌚を䞎えたす。




なぜなら No. 1を詊した埌、すでにある皋床の経隓がありたした。javaのみを䜿甚しおpostgisに実装したプロセスを郚分的に繰り返す必芁がありたした。 実際、JTSに実装されおいる空間むンデックスRTreeずQuadTreeのみが必芁です。 そしお、ゞオメトリずラむン䞊のポむントを分離するなど、ゞオメトリを操䜜するためのいく぀かの実甚的な方法。



そのため、OSMデヌタを2段階で凊理したす。

1 OSMファむルからゞオメトリを取埗し、断片にカットしたす-幅0.1床のストリップ。 これにより、タスクを自然にパヌツに分割し、同時に境界のゞオメトリを簡玠化できたす。 ぀たり、40,000のセグメントを持぀ロシア連邊の1぀の境界の代わりに、1ダヌスのセグメントを持぀各1,500個のピヌス​​を取埗したす。 各ストリップの境界線ポリゎンの数も数十の領域になりたす。

2第2段階では、ポむントが境界のポリゎンに入るこずを期埅し、最も近い通り、最も近い郜垂を探したす。 各「ストリップ」はそれぞれ個別に凊理され、このステヌゞはスレッド/ノヌド間で䞊列化されたす。



その結果、興味のあるポむント、通り、郜垂、囜境、家のJSON蚘述を取埗したす。



これは、POIの説明がどのように芋えるかです
 { "id": "poipnt-3372930671-n600379459", "ftype": "poipnt", "timestamp": "2014-05-14T15:22:11.785Z", "poiTypes": ["police"], "boundaries": { "index_name": ",  ,  ", "text": " ,  , ", "langs": [], "longText": " ,  ,  , ", "boundariesHash": -410546539, "parts": [{ "lvl": "boundary:2", "names": { //         "int_name": "Russia", "official_name": " ", "name": "" }, "lnk": "admbnd-2864649470-r60189", "name": " ", "lvl-size": 130 }, { "lvl": "boundary:4", "names": { "name:en": "Nizhny Novgorod Oblast", "name:ru": " ", "name": " ", "name:de": "Oblast Nischni Nowgorod" }, "lnk": "admbnd-3018389977-r72195", "name": " ", "lvl-size": 110 }, { "lvl": "boundary:6", "names": { "name:ru": " ", "name": " ", "official_name": "  " }, "lnk": "admbnd-3704710510-r2031968", "name": " ", "lvl-size": 90 }, { "lvl": "place:town", "names": { "name:hu": "Szarov", "name:en": "Sarov", "name:ru": "", "name:pl": "Sarow", "name": "", "name:de": "Sarow" }, "lnk": "plcbnd-3118671325-r1428992", "name": "", "lvl-size": 70 }] }, "properties": { "name": "", "amenity": "police" }, "type": "Feature", "metainfo": { "id": 600379459, "type": "node" }, "geometry": { "type": "Point", "coordinates": [43.323823, 54.935209] } }
      
      









家の説明䜏所は次のようになりたす
 { "id": "adrpnt-0642964090-w129096772", "ftype": "adrpnt", "timestamp": "2014-05-14T15:31:38.778Z", "nearbyStreets": [{ "id": "hghway-3750745956-w128994466", "properties": { "highway": "unclassified", "name": " " } }, { "id": "hghway-1683350308-w129293134", "properties": { "kladr:user": "87005000001000100", "surface": "concrete", "highway": "tertiary", "name": "  ", "oneway": "no" } }, { "id": "hghway-0059099168-w129293131", "properties": { "highway": "unclassified", "name": " " } }, { "id": "hghway-0069632087-w129293121", "properties": { "kladr:user": "87005000001000100", "surface": "concrete", "highway": "tertiary", "name": "  ", "oneway": "no" } }, { "id": "hghway-4111943004-w128995822", "properties": { "highway": "residential", "name": " " } }], "properties": { "building": "yes", "building:levels": "2", "sport": "swimming", "amenity": "swimming_pool", "addr:street": "  ", "addr:housenumber": "14" }, "nearestCity": { "id": "plcdln-2842041450-n1575069719", "properties": { "name:fr": "Providenia", "addr:postcode": "689251", "name:ru": "", "name:en": "Provideniya", "name:nl": "Providenia", "name:pl": "Prowidienija", "name:it": "Providenija", "name:es": "Providéniya", "addr:country": "RU", "name": "", "name:de": "Prowidenija", "addr:region": "  ", "place": "town" } }, "type": "Feature", "addresses": [{ "index_name": " 14,   , ,  ,   ,  ", "text": " ,   ,  , ,   ,  14", "langs": [], "longText": " ,   ,   ,  , ,   ,  14", "parts": [{ "lvl": "postcode", "name": "", "lvl-size": 55 }, { "lvl": "boundary:2", "names": { //   }, "lnk": "admbnd-2864649470-r60189", "name": " ", "lvl-size": 130 }, { "lvl": "boundary:3", "names": { "name:sv": "FjÀrran österns federala distrikt", "name:en": "Far Eastern Federal District", "name:ru": "  ", "name:ja": "極東連邊管区", "name:es": "Distrito federal del Lejano Oriente", "name:de": "Föderationskreis Ferner Osten", "short_name": "", "name:vi": "Vùng liên bang Viễn ĐÎng", "name:pt": "Distrito Federal Oriental", "name:fr": "District fédéral extrême-oriental", "name:uk": "і  ", "name:nl": "Federaal District Verre Oosten", "name:zh": "遠東聯邊管區", "name:it": "Distretto Federale dell'Estremo Oriente", "name:pl": "Dalekowschodni Okręg Federalny", "name": "  " }, "lnk": "admbnd-2969582277-r1221185", "name": "  ", "lvl-size": 120 }, { "lvl": "boundary:4", "names": { "name:sv": "Tjuktjien", "name:en": "Chukotka Autonomous Okrug", "name:ru": "  ", "name:ja": "チュクチ自治管区", "name:es": "Chukotka", "name:de": "Autonomer Kreis der Tschuktschen", "short_name": "", "name:vi": "Khu tá»± trị Chukotka", "name:fr": "Tchoukotka", "name:uk": "  ", "name:nl": "Tsjoekotka", "name:zh": "楚科奇自治区", "name:it": "Circondario autonomo della Čukotka", "name:pl": "Czukocki Okręg Autonomiczny", "int_name": "Chukotka Autonomous Okrug", "name": "  " }, "lnk": "admbnd-4289483775-r151231", "name": "  ", "lvl-size": 110 }, { "lvl": "boundary:6", "names": { "name:ru": " ", "name": " " }, "lnk": "admbnd-2373015928-r1949882", "name": " ", "lvl-size": 90 }, { "lvl": "place:town", "names": { "name": "" }, "lnk": "plcbnd-3753535756-w129289823", "name": "", "lvl-size": 70 }, { "lvl": "street", "strtUID": -30263303, "lnk": "hghway-1683350308-w129293134", "names": { "name": "  " }, "name": "  ", "lvl-size": 20 }, { "lvl": "hn", "names": {}, "lnk": "adrpnt-0642964090-w129096772", "name": " 14", "lvl-size": 10 }], "addr-scheme": "regular" }], "metainfo": { "id": 129096772, "type": "way", "fullGeometry": { "type": "Polygon", "coordinates": [ [ [-173.2301084, 64.4217729], [-173.229167, 64.4220204], [-173.2293185, 64.4221278], [-173.2298729, 64.421982], [-173.2299223, 64.4220171], [-173.2302113, 64.4219379], [-173.2300846, 64.4218517], [-173.2301819, 64.421825], [-173.2301084, 64.4217729] ] ] } }, "geometry": { "type": "Point", "coordinates": [-173.22972832, 64.42195376] } }
      
      









䞭間デヌタのストレヌゞ圢匏はjsongzipで圧瞮です。 これにより、たず、デバッグが倧幅に簡玠化されたす。 単玔なzcat、zgrepで䞭間結果を芋るこずができたす。 第二に、もしあればサヌドパヌティの開発者の生掻を簡玠化したす。



出力では、postgis + sphynxバンドルのcsvここではpostgisは䞍芁かもしれたせんが、このバンドルでリバヌスゞオコヌダヌを実行するず䟿利ですずelasticsearchのjsonを生成したすリバヌスゞオコヌディングはelasticsearch自䜓を䜿甚しお実行できたす。



6 GBのRAMず玄5 GBのディスク容量で、RFの凊理に玄2時間かかりたす。 時間を犠牲にするこずで、より少ないラムで収瞮できたす。 私に知られおいるアナログは2日間を過ごしたす。

倚くのセクションは、私のクラス実装を䜿甚しおカスタマむズし拡匵する予定の拡匵機胜の数、groovyの拡匵機胜を裏切るこずができたす。

デヌタ凊理アプリケヌションは1぀の実行可胜jarであり、远加の䟝存関係をむンストヌルする必芁はありたせん。

珟時点では、倚くのコマンドラむンパラメヌタヌを䜿甚しお起動するためのかなり掗緎された構文がありたすが、将来は1行のjava -jar gazetteer.jar russia.configで起動し、クラスタヌの䜜業ノヌドずしおさらに改善する予定です。



自転車github.com/kiselev-dv/gazetteerぞのリンク



私は怜玢技術が苊手なので、elasticsearchに読み蟌たれる怜玢自䜓はただ䞍十分です。 この皮のデヌタの操䜜ず、ゞオデヌタの怜玢゚ンゞンの蚭定の実隓に興味のある人がハブにいる堎合-ようこそ。



プロゞェクトは2぀の郚分で構成されおいたす。

Gazetteer-デヌタ凊理。

GazetteerWeb-elasticsearchの䞊郚にあるAPITomcatでは珟圚-今埌はnettyを䜿甚する予定です



All Articles