概要
標準的な位置情報データでは、近くに何があるかはわかりますが、「このエリアは自分にとってどのくらい良いのか」というより重要な質問に答えることはできません。ユーザーのニーズは複雑です。幼い子供のいる家族と、犬を飼っている若い専門職では、優先順位が異なります。お客様が自信を持って意思決定できるように、これらの具体的なニーズを反映した分析情報を提供する必要があります。カスタム ロケーション スコアは、この価値を提供し、差別化されたユーザー エクスペリエンスを生み出すための強力なツールです。
このドキュメントでは、BigQuery の Places Insights データセットを使用して、カスタムの多面的な位置情報スコアを作成する方法について説明します。POI データを意味のある指標に変換することで、不動産、小売、旅行のアプリケーションを充実させ、ユーザーが必要とする関連情報を提供できます。また、Gemini Developer API を使用して位置情報のスコアを計算することもできます。
カスタマイズされたスコアでビジネス価値を高める
次の例は、位置情報の生データをユーザー中心の強力な指標に変換して、アプリを強化する方法を示しています。
- 不動産開発業者は、「家族向けスコア」や「通勤者向けスコア」を作成して、購入者や賃借人がライフスタイルに合った最適な近隣地域を選択できるようにします。これにより、ユーザー エンゲージメントの向上、質の高い見込み顧客の獲得、コンバージョンの迅速化につながります。
- 旅行・宿泊施設のエンジニアは、「ナイトライフ スコア」や「観光客向けパラダイス スコア」を構築して、旅行者が自分の旅行スタイルに合ったホテルを選べるようにし、予約率と顧客満足度を高めることができます。
- 小売アナリストは「フィットネスとウェルネスのスコア」を生成して、近くにある相補的なビジネスに基づいて新しいジムや健康食品店の最適な場所を特定し、適切なユーザー層をターゲットに設定する可能性を最大限に高めることができます。
このガイドでは、BigQuery で Places データを使用してあらゆる種類のカスタム ロケーション スコアを構築するための柔軟な 3 部構成の方法論について説明します。このパターンを説明するために、家族向けスコアとペットオーナー向けパラダイス スコアという 2 つの異なるスコアの例を作成します。このアプローチでは、場所の数だけでなく、Places Insights データセット内の詳細な属性を活用できます。営業時間、子ども連れに適しているかどうか、犬の同伴が可能かどうかなどの情報を使用して、ユーザーにとって有益で高度な指標を作成できます。
ソリューションのワークフロー

このチュートリアルでは、単一の強力な SQL クエリを使用して、任意のユースケースに適応できるカスタム スコアを構築します。このプロセスを、架空のアパートのリスティングのセットに対して 2 つのスコアの例を作成することで説明します。
前提条件
始める前に、こちらの手順に沿ってプレイス分析を設定してください。
1. 基盤を確立する: 関心のある場所
スコアを作成する前に、分析する場所のリストが必要です。まず、このデータが BigQuery のテーブルとして存在することを確認します。各位置情報に一意の識別子と、その座標を保存する GEOGRAPHY 列が必要です。
次のようなクエリを使用して、スコアリングする位置情報のテーブルを作成してデータを入力できます。
CREATE OR REPLACE TABLE `your_project.your_dataset.apartment_listings`
(
id INT64,
name STRING,
location GEOGRAPHY
);
INSERT INTO `your_project.your_dataset.apartment_listings` VALUES
(1, 'The Downtowner', ST_GEOGPOINT(-74.0077, 40.7093)),
(2, 'Suburban Oasis', ST_GEOGPOINT(-73.9825, 40.7507)),
(3, 'Riverside Lofts', ST_GEOGPOINT(-73.9470, 40.8079))
-- More rows can be added here
. . . ;
位置情報データに対して SELECT * を実行すると、次のようになります。

2. コアロジックを開発する: スコアリング クエリ
場所が特定できたら、次のステップとして、カスタム スコアに関連する近くの場所を検索、フィルタ、カウントします。これはすべて、単一の SELECT ステートメント内で行われます。
地理空間検索で近くにあるものを探す
まず、Places Insights データセットから、各店舗から一定の距離内にあるすべての場所を見つける必要があります。この場合は、BigQuery 関数 ST_DWITHIN が最適です。apartment_listings テーブルと places_insights テーブルの間で JOIN を実行して、半径 800 メートル以内のすべての場所を見つけます。LEFT JOIN を使用すると、近くに一致する場所が見つからなくても、元の場所がすべて結果に含まれます。
高度な属性で関連性をフィルタする
ここでは、スコアの抽象的なコンセプトを具体的なデータフィルタに変換します。2 つのスコア例では、基準が異なります。
- 「ファミリー フレンドリー スコア」では、子どもに特に適した公園、博物館、レストランを重視しています。
- 「ペットオーナーの楽園スコア」では、公園、動物病院、ペットショップ、犬同伴可のレストランやカフェを重視しています。
これらの特定の属性は、クエリの WHERE 句で直接フィルタできます。
各店舗の分析情報を集計する
最後に、各アパートメントについて、関連する場所がいくつ見つかったかをカウントする必要があります。GROUP BY 句は結果を集計し、COUNTIF 関数は各スコアの特定の条件に一致する場所をカウントします。
次のクエリは、これらの 3 つの手順を組み合わせて、1 回のパスで両方のスコアの生カウントを計算します。
-- This Common Table Expression (CTE) will hold the raw counts for each score component.
WITH insight_counts AS (
SELECT WITH AGGREGATION_THRESHOLD -- Correctly includes the mandatory aggregation threshold
apartments.id,
apartments.name,
COUNTIF(places.primary_type = 'park') AS park_count,
COUNTIF(places.primary_type = 'museum') AS museum_count,
COUNTIF(places.primary_type = 'restaurant' AND places.good_for_children = TRUE) AS family_restaurant_count,
COUNTIF(places.primary_type IN ('veterinary_care', 'pet_store')) AS pet_service_count,
COUNTIF(places.allows_dogs = TRUE) AS dog_friendly_place_count
FROM
`your_project.your_dataset.apartment_listings` AS apartments
LEFT JOIN
`your-project.places_insights___us.places` AS places -- Corrected table name for the US dataset
ON ST_DWITHIN(apartments.location, places.point, 800) -- Find places within 800 meters
GROUP BY
apartments.id, apartments.name
)
SELECT * FROM insight_counts;
このクエリの結果は次のようになります。

次のセクションでは、これらの結果に基づいて説明します。
3. スコアを作成する
これで、場所の数と、各場所タイプの重み付けが各場所で取得できたので、カスタムの場所スコアを生成できます。このセクションでは、BigQuery で独自のカスタム計算を使用する方法と、Gemini Developer API を使用する方法の 2 つのオプションについて説明します。
オプション 1: BigQuery で独自のカスタム計算を使用する
前のステップの未加工のカウントは有益ですが、目標は単一のユーザー フレンドリーなスコアです。最後のステップは、重みを使用してこれらのカウントを組み合わせ、結果を 0 ~ 10 のスケールに正規化することです。
カスタム ウェイトの適用 ウェイトの選択は、芸術と科学の両面があります。ビジネス上の優先事項や、ユーザーにとって最も重要だと考えられることを反映する必要があります。「家族向け」スコアの場合、公園は博物館の 2 倍重要であると判断するかもしれません。最良の仮説から始め、ユーザー フィードバックに基づいてイテレーションを行います。
スコアの正規化 次のクエリでは、2 つの共通テーブル式(CTE)を使用します。1 つ目は以前と同様に未加工のカウントを計算し、2 つ目は重み付けされたスコアを計算します。最後の SELECT ステートメントは、重み付けされたスコアに対して最小値と最大値の正規化を実行します。例の apartment_listings テーブルの location 列が出力され、地図上のデータ可視化が可能になります。
WITH
-- CTE 1: Count nearby amenities of interest for each apartment listing.
insight_counts AS (
SELECT WITH AGGREGATION_THRESHOLD
apartments.id,
apartments.name,
COUNTIF(places.primary_type = 'park') AS park_count,
COUNTIF(places.primary_type = 'museum') AS museum_count,
COUNTIF(places.primary_type = 'restaurant' AND places.good_for_children = TRUE) AS family_restaurant_count,
COUNTIF(places.primary_type IN ('veterinary_care', 'pet_store')) AS pet_service_count,
COUNTIF(places.allows_dogs = TRUE) AS dog_friendly_place_count
FROM
`your_project.your_dataset.apartment_listings` AS apartments
LEFT JOIN
`your-project.places_insights___us.places` AS places
ON ST_DWITHIN(apartments.location, places.point, 800)
GROUP BY
apartments.id,
apartments.name
),
-- CTE 2: Apply custom weighting to the amenity counts to generate raw scores.
raw_scores AS (
SELECT
id,
name,
(park_count * 3.0) + (museum_count * 1.5) + (family_restaurant_count * 2.5) AS family_friendliness_score,
(park_count * 2.0) + (pet_service_count * 3.5) + (dog_friendly_place_count * 2.5) AS pet_paradise_score
FROM
insight_counts
)
-- Final Step: Normalize scores to a 0-10 scale and rejoin to retrieve the location geometry.
SELECT
raw_scores.id,
raw_scores.name,
apartments.location,
raw_scores.family_friendliness_score,
raw_scores.pet_paradise_score,
-- Normalize Family Score using a MIN/MAX window function.
ROUND(
COALESCE(
SAFE_DIVIDE(
(raw_scores.family_friendliness_score - MIN(raw_scores.family_friendliness_score) OVER ()),
(MAX(raw_scores.family_friendliness_score) OVER () - MIN(raw_scores.family_friendliness_score) OVER ())
) * 10,
0
),
2
) AS normalized_family_score,
-- Normalize Pet Score using a MIN/MAX window function.
ROUND(
COALESCE(
SAFE_DIVIDE(
(raw_scores.pet_paradise_score - MIN(raw_scores.pet_paradise_score) OVER ()),
(MAX(raw_scores.pet_paradise_score) OVER () - MIN(raw_scores.pet_paradise_score) OVER ())
) * 10,
0
),
2
) AS normalized_pet_score
FROM
raw_scores
JOIN
`your_project.your_dataset.apartment_listings` AS apartments
ON raw_scores.id = apartments.id;
クエリの結果は次のようになります。最後の 2 つの列は正規化されたスコアです。

正規化されたスコアについて
この最終的な正規化ステップがなぜ重要なのかを理解することが重要です。重み付けされた未加工のスコアは、場所の都市密度に応じて 0 から非常に大きな数値まで変化します。コンテキストがないと、ユーザーにとって 500 のスコアは意味がありません。
正規化により、これらの抽象的な数値が相対的なランキングに変換されます。結果を 0 ~ 10 の範囲にスケーリングすることで、特定のデータセット内の各ロケーションが他のロケーションと比較してどう評価されているかをスコアで明確に把握できます。
- スコア 10 は、最も高い生スコアを持つ場所に割り当てられ、現在のセットで最適なオプションとしてマークされます。
- スコア 0 は、未加工のスコアが最も低い場所に割り当てられ、比較の基準値となります。これは、その場所のアメニティがゼロであることを意味するのではなく、評価対象の他のオプションと比較して最も適していないことを意味します。
- その他のスコアは、その間に比例して配置されるため、ユーザーはオプションをひと目で比較できます。
オプション 2: Gemini Developer API を使用する
BigQuery で固定の数式を使用する代わりに、Gemini Developer API を使用すると、ニュアンスのあるカスタム ロケーション スコアを計算できます。
方法 1 は、アメニティの数に基づく純粋な定量的スコアリングには優れていますが、質的データを簡単に考慮することはできません。Gemini を使用すると、Places Insights クエリの数値と、アパートのリスティングのテキスト説明などの非構造化データを組み合わせることができます(例: 「この場所は家族連れに適しており、夜は静かです」)や、特定のユーザー プロファイルの好み(「このユーザーは家族のために予約しており、中心部の静かなエリアを希望しています」)を使用して、よりニュアンスのあるスコアを生成します。
Gemini 用のデータを準備する
この方法を使用するには、BigQuery 集計の結果(ステップ 2)を Markdown 形式に変換し、Listing Description などの定性データと組み合わせます。
この例では、特性が大きく異なる 2 つのリスティングがあります。また、Target User Profile を含めて、誰のスコアを計算しているかを Gemini に伝えます。
## Listing 1: The Downtowner
* **ID:** 1
* **Amenity Counts:**
* Parks: 70
* Museums: 34
* Family-Friendly Restaurants: 141
* **Listing Description:** A vibrant apartment in the heart of the city.
Great for nightlife, but can be noisy on weekends. Close to several
small playgrounds.
* **Target User Profile:** Young family with a toddler, looking for a
balance of activity and quiet.
---
## Listing 2: Suburban Oasis
* **ID:** 2
* **Amenity Counts:**
* Parks: 34
* Museums: 30
* Family-Friendly Restaurants: 318
* **Listing Description:** Quiet, tree-lined street. Large backyard and easy
walking distance to a major park and elementary school.
* **Target User Profile:** Young family with a toddler, looking for a
balance of activity and quiet.
システム指示
Gemini は、これらのさまざまなデータポイントの重みを判断するために、システム指示を必要とします。特定の設備がどの程度重要であるかをモデルに明示的に伝え、テキストの説明の感情を考慮するように指示することもできます。
You are an expert real estate analyst. Your goal is to generate a
"Family-Friendliness Score" between 0.0 and 10.0 for a list of apartment
locations.
For each location, you will be given quantitative data (amenity counts)
and qualitative data (descriptions and user profiles).
Scoring Criteria:
- High importance: Proximity to parks and a high count of family-friendly
restaurants.
- Medium importance: Proximity to museums.
- Negative modifiers: Descriptions indicating excessive noise, lack of
safe play areas, or mismatch with the user profile.
- Positive modifiers: Descriptions indicating quiet areas, safe streets,
or extra space (e.g., backyards).
Analyze the provided data and generate scores based on these criteria.
構造化出力
AI をアプリケーションに統合する際の信頼性を確保するには、出力形式をプロンプトだけに依存しないようにする必要があります。代わりに、Gemini の構造化出力機能を使用してください。responseSchema を指定すると、モデルがシステム要件に正確に一致する、解析可能なクリーンな JSON 配列を返すことが保証されます。
この例では、次のスキーマを適用できます。
{
"type": "ARRAY",
"items": {
"type": "OBJECT",
"required": ["location_id", "name", "score", "reasoning"],
"properties": {
"location_id": {"type": "STRING"},
"name": {"type": "STRING"},
"score": {
"type": "NUMBER"
},
"reasoning": {
"type": "STRING"
}
}
}
}
出力例
定義された responseSchema を含むプロンプトを送信すると、Gemini はアプリケーションで直接使用できる構造化された JSON 配列を返します。
出力で、Gemini がトレードオフをどのように処理しているかを確認します。「The Downtowner」は公園の数が非常に多いですが、Gemini は「週末は騒がしい」という説明を幼児にとって大きなマイナスと判断しています。一方、「郊外のオアシス」は、優れたアメニティの密度と、「静かな並木道」などの該当する定性的な特徴を組み合わせることで、ほぼ完璧なスコアを獲得しています。
[
{
"id": 1,
"location_name": "The Downtowner",
"analysis_notes": "Excellent amenity counts (parks, restaurants, museums), fulfilling
quantitative metrics. However, the qualitative data indicates excessive weekend
noise and a strong nightlife focus, conflicting directly with the target
user's need for quiet and suitability for a toddler. This mismatch
significantly lowers the final score.",
"family_friendliness_score": 5.5
},
{
"id": 2,
"location_name": "Suburban Oasis",
"analysis_notes": "Outstanding quantitative data, especially the very high count of
family-friendly restaurants. The qualitative description (quiet, tree-lined street,
large backyard, proximity to elementary school and major park) aligns perfectly with
and exceeds the needs of the target family profile. High positive modifiers
result in a near-perfect score.",
"family_friendliness_score": 9.8
}
]
この方法では、各ユーザーに合わせた、わかりやすいパーソナライズされたスコアを配信できます。
4. スコアを地図上に可視化する
BigQuery Studio には、GEOGRAPHY 列を含むクエリ結果の統合マップの可視化機能が含まれています。クエリは location 列を出力するため、スコアをすぐに可視化できます。
[Visualization] タブをクリックすると地図が表示され、[Data Column] プルダウンで可視化する場所のスコアを制御できます。この例では、normalized_pet_score はオプション 1 の例から可視化されています。この例では、apartment_listings テーブルにロケーションが追加されています。

データを可視化すると、作成したスコアに最適な場所が一目でわかります。この場合、緑色の円が濃いほど normalized_pet_score が高い場所を示しています。Places Insights データの可視化オプションの詳細については、クエリ結果を可視化するをご覧ください。
まとめ
これで、ニュアンスのあるロケーション スコアを作成するための強力で再現可能な方法論が確立されました。まず、位置情報を使用して、ST_DWITHIN で近くの場所を検索し、good_for_children や allows_dogs などの高度な属性でフィルタし、COUNTIF で結果を集計する単一の SQL クエリを BigQuery で作成しました。カスタムの重みを適用して結果を正規化することで、実用的な詳細な分析情報を提供する、ユーザー フレンドリーな単一のスコアが生成されました。このパターンを直接適用して、位置情報の元データを大きな競争優位性に変換できます。
次のアクション
それでは、実際に構築してみましょう。このチュートリアルでは、テンプレートを提供します。Places Insights スキーマで利用可能な豊富なデータを使用して、ユースケースに最も必要なスコアを作成できます。構築できる他のスコアを検討してください。
- 「ナイトライフ スコア」:
primary_type(bar、night_club)、price_level、深夜の営業時間に関するフィルタを組み合わせて、夜間の活気のあるエリアを見つけます。 - 「フィットネス&ウェルネス スコア」: 近くの
gyms、parks、health_food_storesをカウントし、serves_vegetarian_foodを含むレストランをフィルタして、健康志向のユーザー向けに場所をスコア付けします。 - 「通勤に便利な場所スコア」:
transit_stationやparkingが近くにたくさんある場所を見つけて、交通機関へのアクセスを重視するユーザーをサポートします。
寄稿者
DevX エンジニア | Henrik Valve