Skip to content

Commit ab1b7cf

Browse files
authored
Merge pull request #21 from jphacks/feat/merge-paths
Feat/merge paths
2 parents e53c810 + 605b567 commit ab1b7cf

File tree

6 files changed

+251
-300
lines changed

6 files changed

+251
-300
lines changed

.vscode/settings.json

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,8 @@
2828
"[python]": {
2929
"editor.defaultFormatter": "charliermarsh.ruff",
3030
"editor.codeActionsOnSave": {
31-
"source.fixAll.ruff": "always",
32-
"source.organizeImports.ruff": "always"
33-
},
34-
"editor.formatOnSave": true
31+
"source.fixAll.ruff": "explicit",
32+
"source.organizeImports.ruff": "explicit"
33+
}
3534
}
3635
}

backend/commons/import_paths.py

Lines changed: 61 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@
99
python commons/import_paths.py
1010
"""
1111

12-
import argparse
1312
import json
1413
import os
1514
import sys
16-
from concurrent.futures import ThreadPoolExecutor, as_completed
1715
from pathlib import Path
1816

1917
from tqdm import tqdm
@@ -48,58 +46,52 @@ def import_path_data(
4846
FileNotFoundError: ファイルが存在しない
4947
ValueError: JSONフォーマットが不正
5048
"""
49+
# ファイル存在チェック
5150
if not os.path.exists(json_path):
5251
raise FileNotFoundError(f"File not found: {json_path}")
5352

54-
# JSONデータを読み込み
53+
# JSONファイルを読み込み
5554
with open(json_path, "r", encoding="utf-8") as f:
5655
data = json.load(f)
5756

58-
# データ形式を判定
57+
# データ形式を判定(Overpass API形式または配列形式)
5958
if isinstance(data, dict) and "elements" in data:
60-
# OpenStreetMap Overpass API形式: {"elements": [...]}
6159
paths_data = data["elements"]
6260
elif isinstance(data, list):
63-
# 配列
6461
paths_data = data
6562
else:
6663
raise ValueError(
6764
"Invalid JSON format: expected object with 'elements' key or array"
6865
)
6966

70-
# wayタイプのみフィルタ
71-
# paths_data = [p for p in paths_data if p.get("type") == "way"]
72-
# print(f" Total ways: {len(paths_data)}")
73-
74-
# 統計情報
67+
# 統計情報の初期化
7568
stats = {
7669
"total": len(paths_data),
7770
"created": 0,
7871
"skipped": 0,
7972
"errors": 0,
8073
}
8174

82-
# 各パスデータをインポート
83-
# print("\nImporting paths...")
84-
# print(f"Batch size: {batch_size} (commits every {batch_size} items)")
85-
75+
# 各パスデータを処理
8676
with tqdm(
8777
paths_data, desc=f"Processing paths in {Path(json_path).name}", unit="path"
8878
) as pbar:
8979
for i, path_data in enumerate(pbar, 1):
9080
try:
81+
# 基本情報を取得
9182
osm_id = path_data.get("id")
9283
path_type = path_data.get("type") or "way"
9384
geometry = path_data.get("geometry", [])
9485

95-
# 既存チェック
86+
# 既存データのチェック
9687
if PathModel.objects.filter(osm_id=osm_id).exists():
9788
if skip_existing:
9889
stats["skipped"] += 1
9990
continue
10091

92+
# データベースへの保存(トランザクション内)
10193
with transaction.atomic():
102-
# Pathオブジェクトを作成
94+
# Pathレコードを作成
10395
bounds = path_data.get("bounds", {})
10496
path = PathModel.objects.create(
10597
osm_id=osm_id,
@@ -110,7 +102,7 @@ def import_path_data(
110102
maxlon=bounds.get("maxlon"),
111103
)
112104

113-
# Geometriesを追加
105+
# ジオメトリ情報を保存
114106
nodes = path_data.get("nodes", [])
115107
for idx, geom in enumerate(geometry):
116108
PathGeometry.objects.create(
@@ -121,7 +113,7 @@ def import_path_data(
121113
sequence=idx,
122114
)
123115

124-
# Tagsを追加
116+
# タグ情報を保存
125117
tags = path_data.get("tags", {})
126118
if tags:
127119
PathTag.objects.create(
@@ -132,31 +124,39 @@ def import_path_data(
132124
kuma=tags.get("kuma"),
133125
)
134126

127+
# 地理情報フィールドを更新
128+
path.update_geo_fields()
129+
path.save(
130+
update_fields=[
131+
"route",
132+
"bbox",
133+
"minlon",
134+
"minlat",
135+
"maxlon",
136+
"maxlat",
137+
]
138+
)
139+
135140
stats["created"] += 1
136141
except Exception as e:
137142
stats["errors"] += 1
138-
pbar.write(f" Error: OSM ID {path_data.get('id', 'Unknown')} - {str(e)}")
143+
pbar.write(f"Error importing OSM ID {path_data.get('id', 'Unknown')}: {str(e)}")
139144

140145
return stats
141146

142147

143148
def main():
144149
"""メイン関数"""
145-
parser = argparse.ArgumentParser(description="登山道データJSONインポートスクリプト")
146-
parser.add_argument(
147-
"--workers",
148-
type=int,
149-
default=1,
150-
help="並列処理のワーカースレッド数 (デフォルト: 1)",
151-
)
152-
args = parser.parse_args()
153150

151+
# データフォルダのパスを設定
154152
data_folder = Path(__file__).parent.parent / "datas" / "paths_merged"
155153

154+
# フォルダ存在チェック
156155
if not data_folder.exists():
157156
print(f"❌ Error: Data folder not found: {data_folder}")
158157
sys.exit(1)
159158

159+
# JSONファイルを検索
160160
files = list(data_folder.glob("*.json"))
161161

162162
if not files:
@@ -166,11 +166,13 @@ def main():
166166
batch_size = 1000
167167

168168
try:
169+
# インポート開始
169170
print("=" * 60)
170-
print("Path Data Import")
171+
print("🚀 Path Data Import Started")
172+
print(f"📁 Found {len(files)} JSON file(s) in {data_folder.name}")
171173
print("=" * 60)
172-
print(f"Found {len(files)} JSON file(s)")
173174

175+
# 統計情報の初期化
174176
total_stats = {
175177
"total": 0,
176178
"created": 0,
@@ -181,56 +183,39 @@ def main():
181183
with tqdm(
182184
total=len(files), desc="Processing JSON files", unit="file"
183185
) as overall_pbar:
184-
with ThreadPoolExecutor(max_workers=args.workers) as executor:
185-
future_to_file = {
186-
executor.submit(
187-
import_path_data, str(json_path), True, batch_size
188-
): json_path
189-
for json_path in files
190-
}
191-
192-
for future in as_completed(future_to_file):
193-
json_path = future_to_file[future]
194-
try:
195-
result = future.result()
196-
# print("\n" + "-" * 60)
197-
# print("📊 File Import Summary")
198-
# print("-" * 60)
199-
# print(f" File: {json_path.name}")
200-
# print(f" Total: {result['total']}")
201-
# print(f" ✅ Created: {result['created']}")
202-
# print(f" ⏭️ Skipped: {result['skipped']}")
203-
# print(f" ❌ Errors: {result['errors']}")
204-
# print("-" * 60)
205-
206-
# 累計を更新
207-
total_stats["total"] += result["total"]
208-
total_stats["created"] += result["created"]
209-
total_stats["skipped"] += result["skipped"]
210-
total_stats["errors"] += result["errors"]
211-
212-
if result["errors"] > 0:
213-
print(
214-
f"\n⚠️ Warning: {result['errors']} errors occurred during import"
215-
)
216-
except Exception as e:
217-
print(f"\n❌ Error processing file {json_path.name}: {e}")
218-
finally:
219-
overall_pbar.update(1)
220-
221-
# 最終サマリー
186+
for json_path in files:
187+
try:
188+
result = import_path_data(str(json_path), True, batch_size)
189+
190+
# 統計を累積
191+
total_stats["total"] += result["total"]
192+
total_stats["created"] += result["created"]
193+
total_stats["skipped"] += result["skipped"]
194+
total_stats["errors"] += result["errors"]
195+
196+
# エラーがあれば警告表示
197+
if result["errors"] > 0:
198+
print(
199+
f"\n⚠️ Warning: {result['errors']} error(s) in {json_path.name}"
200+
)
201+
except Exception as e:
202+
print(f"\n❌ Fatal error processing {json_path.name}: {e}")
203+
finally:
204+
overall_pbar.update(1)
205+
206+
# 最終結果の表示
222207
print("\n" + "=" * 60)
223-
print("📊 Total Import Summary")
224-
print("=" * 60)
225-
print(f" Files: {len(files)}")
226-
print(f" Total: {total_stats['total']}")
227-
print(f" ✅ Created: {total_stats['created']}")
228-
print(f" ⏭️ Skipped: {total_stats['skipped']}")
229-
print(f" ❌ Errors: {total_stats['errors']}")
208+
print("Import Completed Successfully")
209+
print(f"📊 Summary:")
210+
print(f" Files processed: {len(files)}")
211+
print(f" Total paths: {total_stats['total']}")
212+
print(f" ✅ Created: {total_stats['created']}")
213+
print(f" ⏭️ Skipped: {total_stats['skipped']}")
214+
print(f" ❌ Errors: {total_stats['errors']}")
230215
print("=" * 60)
231216

232217
except Exception as e:
233-
print(f"\nError occurred: {e}")
218+
print(f"\nFatal error occurred: {e}")
234219
import traceback
235220

236221
traceback.print_exc()

backend/commons/update_paths.py

Lines changed: 0 additions & 49 deletions
This file was deleted.

0 commit comments

Comments
 (0)