>100 Views
March 31, 26
スライド概要
2026/3/31(火) 19:00 〜 21:00 開催
Microsoft Data Analytics Day(Online) 勉強会 202603
https://sqlserver.connpass.com/event/386300/
博士(情報学)。2012年に修士号を取得した後、西日本電信電話株式会社に入社。プライベートクラウド基盤やアプリケーション開発を経験した後、様々な技術(NW、サーバ、クラウド、プログラミング)を組合せることで、データ活用を推進するためのプラットフォームを運営。2019年から社会人ドクターとして研究活動を行い、2023年に博士号を取得。「実社会に役立つデータ活用」を推進する技術者兼研究者。
© 2026 NTT West, Inc. All Rights Reserved. Microsoft製品を用いた数理最適化 アプリケーションの実装の中身 on Fabric Microsoft Data Analytics Day(Online) 勉強会 2026/03 2026/3/31 高須賀 将秀
© 2026 NTT West, Inc. All Rights Reserved. 2 /18 自己紹介 たかすか まさひで 高須賀 将秀 博士(情報学)(2023/3) 研究分野:組合せ最適化,数理最適化,オペレーションズ・リサーチ(OR),グラフ理論 所属:NTT西日本 デジタル改革推進部(2021/8~), 法政大学 デザイン工学部 兼任講師(2024/4~),個人事業(Udemy講師等)(2024/6~) 業務:データドリブン経営を牽引する立場 ・データ活用基盤のシステム開発 ・データ分析手法の研究 ・データ分析活用事例の提案 ・デジタル人材育成 資格:クラウド資格(AWS全冠,Azure全冠,GCP全冠), 受賞:AWS Community Builders(2026),AWS All Certifications Engineers(2024, 2025), 高須賀将秀のホームページ Microsoft Top Partner Engineer Award(2024),Microsoft Innovative Educator Experts 2025-2026, Google Cloud Partner Top Engineer(2026),Google Cloud Partner All Certification Holders(2025), Jagu‘e’r Award 優秀賞(2025),Snowflake Squad(2024, 2025), Microsoft Certified Trainer(MCT)
© 2026 NTT West, Inc. All Rights Reserved. 3 /18 私の研究(博論)内容 ◼ 与えられた全ての工事に対して立会者の割当を決定する問題である ◼ 移動距離や立会者のスキル等の様々な条件を考慮し割当を決定している ◼ 条件は万人共通の条件もあれば手配者の思考や嗜好によって異なるものもある 入力 出力 工事4 工事1 1 工事2 4 手配者 工事5 2 1 工事6 3 工事7 工事8 8 工事9 6 工事5 数理モデル 5 工事6 工事3 手配者 の思考/嗜好 = 7 工事2 4 2 5 工事3 立会者1~4 工事4 工事1 立会者4 3 工事7 立会者1 7 立会者2 工事8 ブラックボックス 化 8 工事9 9 9 立会者3 6
© 2026 NTT West, Inc. All Rights Reserved. 4 /18 私の研究(博論)内容 ◼ 高度な技能を有している手配者により意思決定が行われている工事立会者手配 業務に対し実用的な手配結果を算出可能な数理モデルを構築した 長期効果 短期効果 付随効果 過去の工事立会者手配業務 デジタルデータ活用による工事立会者手配業務 人件費 年間1億(関東エリア:年間6万件) 年間0.1億(関東エリア:年間6万件)(想定) 品質 年間工事事故5件 年間工事事故0件(想定) 総移動時間 11,424 s(3.2 h) 11,593 s(3.2 h)※1 総割当ペナルティ 163 pt 81 pt※1 手配時間 3時間2回/1日 5分×2回/1日 やり方 アナログ(手書き) デジタル 手配結果 ※1:数理モデル4で総移動時間を重視すると, 総合移動時間10,697 s, 総品質146 ptとなる.
© 2026 NTT West, Inc. All Rights Reserved. 5 /18 数理最適化アプリを作ってみた 入力部(住所の保存) ・住所のジオコーディング取得 ・住所情報の保存 アルゴリズム(つまり解の探索方法)の選択部 ・Cortex利用 ・厳密解法 ・メタヒューリスティクス 等 20260129_Microsoft Data Analytics Day ・皆さんもお手元で確認できます ・ただし,Microsoft Fabricへの情 報保存 は皆さんで共用のため注意 ・そのため,この場は,Read部分 (読み込んだ住所一覧,保存済み のデータを表示等))のみ確認を推 奨 ・App Serviceのリソースの関係でう まく地図が表示されない場合あり ・以下アルゴリズムは利用未推奨(時 間制限付き全探索,完全全列挙型 アルゴリズム(全解保存)) 計算処理部 ・選択したアルゴリズムに従った解の探索過程出力 ・最終的な結果の出力 解の可視化部 ・最終的な結果を地図に表示 ・複数の解が出た場合もその結果を表示 https://poccloudstappfabrictsp. azurewebsites.net/ Snowflake版 Microsoft Fabric版
© 2026 NTT West, Inc. All Rights Reserved. Fabric Notebookでの実装 • Fabric上のNotebookで実装する • 基本,同一ワークスペース内のユーザに対してのみしか共有できない 6 /18
© 2026 NTT West, Inc. All Rights Reserved. 7 /18 数理最適化アプリを作ってみた • オープンなサービスとして提供可能なアプリの実装について https://poccloudstappfabrictsp. azurewebsites.net/ Microsoft Fabric版
© 2026 NTT West, Inc. All Rights Reserved. 8 /18 アーキテクチャ ・数理最適化による計算機能部 ・GurobiやPuLP ・メタヒューリスティクスアルゴリズム ・Fabricのデータを用いてデータ可視 化(今回は未対象,Frontの Streamlitで実装) ・App Service(Container)利用 ・最適化計算でGurobi利用 ・Fabricへのデータ書き込みでodbcド ライバ利用 ・Fabric ウェアハウスのSQLエンドポイント経由 でデータを読み書き ・Fabricへの認証にEntra IDを利用 カテゴリ 技術 用途 フロントエンド Streamlit WebUI構築 データ基盤 Microsoft Fabric Warehouse データ永続化 AI Azure OpenAI (GPT-4o) 住所→座標変換、TSP最適化 認証 Azure AD / ClientSecretCredential サービス間認証 接続 pyodbc + ODBC Driver 18 DB接続 可視化 pydeck, plotly 地図・グラフ表示 最適化 scipy, sklearn 数値計算・ML
© 2026 NTT West, Inc. All Rights Reserved. 9 /18 App Service(Container) • App Service にはContainer とCode の2種類あるが,独自ミドルウェア・ツールチェイン対応 (odbc driver)が必要なため,App service(Container)を採用 • 独自ミドルウェア・ツールチェイン対応が不要な場合,簡単にデプロイ可能なApp Service(Code) を使うことをお勧めする Build Run Runのみ app.py ・Streamlit GUI ・Fabric書き込み ・データ可視化 等 requirements.txt ・streamlit等 Dockerfile ・odbc driver ・依存関係 等 Docker File Docker Image Docker Container
© 2026 NTT West, Inc. All Rights Reserved. App Service(Container) • VSCodeからAzure DevOps Reposにコンテナファイルをpushし, App Serviceにデプロイ 10 /18
© 2026 NTT West, Inc. All Rights Reserved.
11 /18
Fabric ウェアハウスへの接続(認証)
• App ServiceのアプリからFabric のウェアハウスへの接続はodbcドライ
バ経由で接続.認証はEntra ID経由.
Azure AD テナント
│
├── アプリ登録 (App Registration)
│ ├── client_id:
アプリケーションID
│ ├── client_secret: クライアントシークレット
│ └── tenant_id:
テナントID
│
└── 権限付与
└── Fabric Warehouse への アクセス権
# 認証情報の設定
AZURE_TENANT_ID = "cfa99149-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
AZURE_CLIENT_ID = "7996d668-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
AZURE_CLIENT_SECRET = "BSE8Q~xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# ClientSecretCredential でトークン取得
credential = ClientSecretCredential(
tenant_id=AZURE_TENANT_ID,
client_id=AZURE_CLIENT_ID,
client_secret=AZURE_CLIENT_SECRET
)
# Fabric Warehouse 用トークンを取得
token = credential.get_token("https://database.windows.net/.default")
access_token = token.token
# ============================================
# Fabric Warehouse接続
# ============================================
def get_new_connection():
"""新しい接続を作成"""
try:
credential = ClientSecretCredential(
tenant_id=AZURE_TENANT_ID,
client_id=AZURE_CLIENT_ID,
client_secret=AZURE_CLIENT_SECRET
)
token = credential.get_token("https://database.windows.net/.default")
access_token = token.token
token_bytes = access_token.encode('utf-16-le')
token_struct = struct.pack(f'<I{len(token_bytes)}s', len(token_bytes), token_bytes)
connection_string = (
f"Driver={{ODBC Driver 18 for SQL Server}};"
f"Server={SQL_ENDPOINT};"
f"Database={WAREHOUSE_NAME};"
f"Encrypt=yes;"
f"TrustServerCertificate=no;"
f"Connection Timeout=30;"
)
conn = pyodbc.connect(connection_string, attrs_before={1256: token_struct})
return conn
except Exception as e:
st.error(f"Fabric Warehouse接続に失敗しました: {e}")
return None
© 2026 NTT West, Inc. All Rights Reserved.
12 /18
Fabric ウェアハウスへのCRUD操作
• App ServiceのアプリからFabric のウェアハウスへの接続はodbcドライ
バ経由で接続.認証はEntra ID経由.
#
============================================
# データベース操作関数
#
============================================
def save_address_to_db(addresses):
"""住所情報をデータベースに保存"""
conn = None
try:
conn = get_new_connection()
if conn is None:
st.error("データベース接続に失敗しました")
return
cursor = conn.cursor()
cursor.execute(f"DELETE FROM
{SCHEMA_NAME}.tsp_address")
conn.commit()
cursor.close()
progress_bar = st.progress(0)
status_text = st.empty()
results = []
successful_count = 0
skipped_count = 0
try:
cursor = conn.cursor()
escaped_address = address.replace("'", "''")
cursor.execute(f"""
INSERT INTO {SCHEMA_NAME}.tsp_address (address,
latitude, longitude, created_at)
VALUES ('{escaped_address}', {lat}, {lon},
CURRENT_TIMESTAMP)
""")
conn.commit()
cursor.close()
successful_count += 1
results.append({
'num': idx + 1,
'address': address,
'status': '保存',
'latitude': f"{lat:.4f}",
'longitude': f"{lon:.4f}"
})
status_text.text(f"保存 {idx + 1}/{len(addresses)}:
{address}")
def get_addresses_from_db():
"""データベースから住所リストを取得"""
conn = None
cursor = None
try:
conn = get_new_connection()
if conn is None:
return []
cursor = conn.cursor()
cursor.execute(f"SELECT address, latitude, longitude FROM
{SCHEMA_NAME}.tsp_address ORDER BY address_id")
results = cursor.fetchall()
return [(row[0], row[1], row[2]) for row in results]
except Exception as e:
st.error(f"住所情報の取得に失敗しました: {e}")
return []
finally:
if cursor:
cursor.close()
if conn:
conn.close()
© 2026 NTT West, Inc. All Rights Reserved.
13 /18
Azure AOAIの設定
• AOAI(gpt-4o)に必要情報を渡して,問題を解いてもらう
# ============================================
# Azure OpenAI クライアント設定
# ============================================
@st.cache_resource
def get_aoai_client():
"""Azure OpenAI クライアントを取得"""
try:
client = AzureOpenAI(
api_key="0b8exxxxxxxxxxxxxxxxxxxxxxxx",
api_version="2023-05-15",
azure_endpoint="https://xxxxxxxxx-eastus2.openai.azure.com/"
)
return client
except Exception as e:
st.error(f"Azure OpenAI接続に失敗しました: {e}")
return None
def solve_tsp_aoai(dist_matrix, addresses, progress_placeholder, history_placeholder):
"""Azure OpenAIを使用してTSPを解く"""
solution_history = []
aoai_client = get_aoai_client()
Return ONLY a valid JSON object:
{{
"route": [0, city1, city2, ..., city{n-1}, 0],
"total_distance": number
}}"""
system_message = """You are an expert algorithm solver specializing in the Traveling
Salesman Problem (TSP).
Your task is to find the shortest route that visits all cities exactly once and returns to the
starting city.
You MUST return ONLY a valid JSON object with NO additional text or explanation."""
user_message = f"""Solve this Traveling Salesman Problem:
NUMBER OF CITIES: {n}
DISTANCE MATRIX:
{json.dumps(dist_matrix_list, indent=2)}
response = aoai_client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": system_message},
{"role": "user", "content": user_message}
],
temperature=0.1,
max_tokens=1000
)
© 2026 NTT West, Inc. All Rights Reserved. 14 /18 Streamlitによる結果の可視化 • Pydeckを用いて結果を地図に描写 def display_route_on_map(addresses, route, key_suffix=""): # 地点データ(赤い丸) points_layer = pdk.Layer( "ScatterplotLayer", data = points_data, get_position = "[lon, lat]", get_radius = 200, get_color = [255, 0, 0], # 赤 pickable = True, ) # ルート(青い線) line_layer = pdk.Layer( "LineLayer", data = route_data, get_source_position = "start", # 始点 get_target_position = "end", # 終点 get_color = [0, 0, 255], # 青 get_width = 3, pickable = False, ) # 地図の中心を自動計算 center_lat = np.mean([lat for lat, lon in locations]) center_lon = np.mean([lon for lat, lon in locations]) view_state = pdk.ViewState( latitude = center_lat, longitude = center_lon, zoom = 12, pitch =0 ) # Streamlitに描画(key指定で複数表示対応) st.pydeck_chart( pdk.Deck(layers=[points_layer, line_layer], initial_view_state=view_state, tooltip={"text": "{label}"}), key=f"map_{key_suffix}" # ← ユニークkeyが必要 )
© 2026 NTT West, Inc. All Rights Reserved. まとめ • 1/29のMicrosoft Data Analytics Day(Online) 勉強会で説明し た数理最適化アプリケーション on Fabric の実装に関する解説を行った • Fabric のNotebook を使うことで,様々な数理最適化アプリケーション を構築できるが,よりオープンな場で共有や利用を行う場合は,Azure サービスを組合せることで,実現可能となる • 本仕組みを応用すれば,テナントやワークスペースを跨るデータの共有も 可能になる.が,SnowflakeのDatasharingのような機能が実装され ると,より使いやすくなると考えている 15 /18
© 2026 NTT West, Inc. All Rights Reserved. 宣伝1 • Global Azure 2026 @ Tokyo のLT枠に参加します • 日時は,2026/4/18 16:15~17:00のどこか • 場所は,日本マイクロソフトのビル(品川)の[Room C+D] https://jazug.connpass.com/event/386399/ 16 /18
© 2026 NTT West, Inc. All Rights Reserved. 宣伝2 • Microsoft AI Tour for Partners でFabric関連を話します! • 日時は,2026/4/8 9:30~17:45のどこか • 場所は,グランドハイアット(六本木) https://www.skilling-hub.com/ja-JP/listing/tokyo 17 /18