ガイド変更履歴HERE SDK API references
ガイド

検索を開始する

HERE SDKは世界中の数億のPOI (施設情報) と住所を含むHEREの広範なグローバルデータセットを活用して、高速で簡単な検索機能を提供します。HERE SDKを使うと、1つのSearchEngineで次のさまざまな検索関連タスクを効率的に実行できます。

  • 場所を検出する:カテゴリー別、または検索語を設定して、世界中のHEREの膨大なデータベースから場所を検索して検出します。
  • 自動候補提示を生成する:検索語を入力して場所を検索することでクエリが補完されます。
  • 住所をリバースジオコーディングする:特定の地理座標に属する住所を検索します。
  • 住所をジオコーディングする:住所に関連付けられた地理座標を検索します。
  • IDで検索する:HEREの場所IDで識別される場所を検索します。
  • ルートに沿って検索する:ルート全体に沿った場所を検索します。
  • ルートに沿ったカテゴリーで検索する:ルート全体に沿ったカテゴリーに基づいて場所を検索します。この機能はベータ版です。
  • what3wordsのサポート (Navigateでのみ使用可能):3語の住所で検索できます。
  • オフラインで検索する (Navigateでのみ使用可能):インターネット接続が利用できない場合は、OfflineSearchEngineに切り替えて、すでにキャッシュに保存されたマップデータまたはプリロードされたオフラインマップデータを検索できます。
  • 私の場所 (Navigateでのみ使用可能):実行時に独自の場所を追加して、オフラインで検索します。

すべての検索バリエーションに共通する機能の 1 つは、検索する場所またはエリアを指定できることです。エリアの設定は、GeoBox で指定された長方形エリア、または GeoCircle で指定された円形エリアを渡すことによって行うことができます。指定されたエリア外にある検索結果候補は、関連するグローバル結果を除き、優先順位が低くなります。たとえば、ベルリンの「マンハッタン」を検索する場合です。ベースとなる検索アルゴリズムは、結果のリストを絞り込み、より速く、より意味のある結果をユーザーに提供できるように最適化されています。

検索はHERE Geocoding and Searchに基づいています。
ジオコーディングと検索の例:SearchEngine.searchByAddress(AddressQuery, ...)
リバースジオコーディングの例:SearchEngine.searchByCoordinates(GeoCoordinates, ...)
検出と検索の例:SearchEngine.searchByText(TextQuery, ...)
自動候補提示の例:SearchEngine.suggestByText(TextQuery, ...)

これらの機能の価格については、「HERE基本プランの価格表」を参照してください。Navigateライセンスを使用している場合、または価格についてご質問がある場合は、お問い合わせください。

各検索リクエストは非同期的に実行されます。オンライン接続が必要です。

SearchEngine を初期化する

HERE の位置情報サービスで提供する膨大な場所のデータベースは、HERE SDK の SearchEngine を使用して簡単にアクセスし探索できます。例を見てみましょう。まず、新しいSearchEngineインスタンスを作成します。

do {
    try searchEngine = SearchEngine()
} catch let engineInstantiationError {
    fatalError("Failed to initialize SearchEngine. Cause: \(engineInstantiationError)")
}

新しいSearchEngineインスタンスを作成すると、エラーがスローされる可能性があります。このようなエラーは、たとえば、HERE SDKの初期化が事前に失敗していた場合に発生する可能性があります。

EV充電検索を拡張する (EVCP 3.0)

EVSearchEngineはオンライン専用であり、Navigateライセンスに加えてHERE EV Charge Points API v3の追加ライセンスが必要です。このエンタイトルメントがない場合、APIは充電メタデータを返しません。

EVSearchEngineは、HERE Place IDを使用してEV充電場所の詳細情報を取得するために単独で実行することも、SearchEngine.setEVInterface(_:)を介してSearchEngineに接続することもできます。これにより、標準の場所検索ごとにplace.details?.evChargingLocationが自動的に公開されます。ユースケースに応じてモードを選択します。EV固有のペイロード (料金、EVSEステータス、トラックの制限など) のみが必要な場合はEVSearchEngine.search(...)を直接呼び出します。EVメタデータをより広範なPOIレスポンスに統合したい場合は、既存のSearchEngineインスタンスに組み込みます。

EvSearchExampleは両方の方法に対応しています。エンジンを組み合わせて拡張する方法を示すとともに、SearchEngineのクエリを使用しない場合にはsearchEVChargingLocationsByPlaceIds()を単独で呼び出すこともできます。

{% codetabs name="Swift", type="swift" -%}
{% raw %}
final class EVSearchExample {

// Provides EVCP 3.0 enrichment; requires an additional EV Charging license beyond Navigate.
private let searchEngine: SearchEngine
private let evSearchEngine: EVSearchEngine

init() throws {
    searchEngine = try SearchEngine()
    evSearchEngine = try EVSearchEngine()
    searchEngine.setEVInterface(evSearchEngine)
}

// Works standalone for EV-only lookups or alongside SearchEngine to enrich generic results.
func searchEVChargingLocationsByPlaceIds(placeIds: [String],
                                         searchOptions: SearchOptions) {
    var evOptions = EVSearchOptions()
    evOptions.additionalFeatures = [
        .energyMix,
        .openingHours
    ]

    // Set options before search call.
    evSearchEngine.setOptions(evOptions)

    // Direct EVSearchEngine call (can be used without SearchEngine involvement).
    evSearchEngine.search(ids: placeIds) { error, locations in
        if let evError = error {
            if evError == .noResultsFound {
                print("No EV charging locations found for the given IDs.")
                return
            }
            print("EV lookup failed: \(evError)")
            return
        }
        locations?.forEach { location in
            let metadata = Metadata()
            metadata.setString(name: "id", value: location.id)
            metadata.setString(name: "connectorGroups", value: "\(location.connectorGroups.count)")
            // Attach metadata to dedicated EV UI elements or map markers.
        }
    }

    // Optional: keep using SearchEngine so every place result surfaces evChargingLocation details.
    let area = TextQuery.Area(inBox: getMapViewGeoBox())
    let textQuery = TextQuery("charging", area: area)
    _ = searchEngine.searchByText(textQuery: textQuery,
                                  options: searchOptions) { searchError, places in
        if let searchError = searchError {
            print("Search error: \(searchError)")
            return
        }
        places?.forEach { place in
            let evDetails = place.details?.evChargingLocation
            // evDetails is populated only when the EV license is active.
        }
    }
}

}
{% endraw %}
{%- endcodetabs %}

同じEVSearchExampleの実装はEVRoutingサンプルアプリにも含まれており、エンドツーエンドで動作を確認できます。

この設定により、使い慣れたSearchEngineのエントリーポイント (カテゴリー、テキスト、またはルート沿い検索) を引き続き使用しながら、該当する場合はコネクター数、料金、オペレーターデータなどのEVCP 3.0情報が自動的に表示されます。EV固有のペイロードのみが必要な場合は、EVSearchEngineのみを使用できます。

場所を検索する

デバイス上に表示されている現在の地図の中心の周囲にあるすべての「ピザ」関連の場所を検索するとします。検索を開始する前に、詳細をいくつか指定する必要があります。

let searchOptions = SearchOptions(languageCode: LanguageCode.enUs,
                                  maxItems: 30)

上記のコードスニペットから、目的のデータを含む新しいSearchOptionsオブジェクトを作成しました。

  • LanguageCodeを設定することで、返される検索結果の言語を指定できます。
  • maxItems は、レスポンスに表示される結果アイテムの最大数を定義するために設定されます。上の例では結果を30件に制限しています。エンジンがリクエストよりも多くの検索結果を検出した場合、最も関連性の高い30件の検索結果のみを返します。

現在のビューポート内のすべての結果を検索するため、ワンボックス検索を実行します。SearchEngineには、検索場所を指定する3つの異なる方法が用意されています。

  • GeoCoordinates で検索する:指定された座標の周囲で非同期検索リクエストを実行し、近くで最も関連性の高い検索結果を提供します。
  • GeoCircleエリア内を検索する:上記と似ていますが、中心の地理座標とメートル単位の半径で定義される、指定された円形エリア内の結果を検索します。
  • GeoBoxエリア内を検索する:上記と似ていますが、パラメーターとして渡された South West 座標と North East 座標によって定義される、指定された長方形エリア内の結果を検索します。

ワンボックス検索は、近くの場所を検出するのに最適です。入力として、さまざまな混合言語 (ラテン語、キリル語、アラビア語、ギリシャ語など) で自由形式のテキストを入力できます。

エリアと用語を一緒に指定して検索できます。queryString にたとえば、"pizza" と設定します。

let queryArea = TextQuery.Area(inBox: getMapViewGeoBox())
let textQuery = TextQuery(queryString, area: queryArea)

ここでは、getMapViewGeoBox() のコードを省略しています。ユースケースに適した任意の GeoBox を作成して渡すことができます。可能な実装は付属のサンプルアプリで確認できます。

指定された地図エリア内の結果が返されます。結果が見つからなかった場合は、グローバル検索結果が返される場合があります。ただし、指定された検索場所に関係なく、著名な都市や州などの関連するグローバルな結果が含まれる場合があります。

クエリ文字列には、検索するコンテンツのテキストによる説明を含めることができます。カンマ区切りの有無にかかわらず、複数の検索語を渡して検索結果を絞り込むことができます。したがって、「Pizza Chausseestraße」と「Pizza, Chausseestraße」はどちらも同じ結果になり、「Chausseestraße」通りにあるピザ レストランのみが検索されます。また、空のクエリ文字列を渡すとエラーとなり、この場合、検索は失敗することにも注意してください。

最後に、非同期で検索を開始できます。

_ = searchEngine.searchByText(textQuery: textQuery,
                        options: searchOptions,
                        completion: onSearchCompleted)

...

// Completion handler to receive search results.
func onSearchCompleted(error: SearchError?, items: [Place]?) {
    if let searchError = error {
        showDialog(title: "Search", message: "Error: \(searchError)")
        return
    }

    // If error is nil, it is guaranteed that the items will not be nil.
    showDialog(title: "Search in viewport for: 'Pizza'.",
               message: "Found  \(items!.count) results.")

    // Add a new marker for each search result on map.
    for searchResult in items! {
        //...
    }
}

または、クロージャー式を使用して、完了ハンドラーをインライン化することもできます。

_ = searchEngine.searchByText(textQuery,
                        options: searchOptions) { (searchError, searchResultItems) in
   // Handle results here.
}

もちろん、HERE SDK で利用可能な他のすべての完了処理についても同じことが可能です。慣例として、このガイドでは、関数呼び出し式を使用して完全なタイプ情報を保持します。

提供されるすべての search() メソッドは TaskHandle を返し、進行中の呼び出しのステータスを確認したり、呼び出しをキャンセルしたりするために必要に応じて使用できます。必要でない場合は、上記のように省略できます。

結果を調べる前に、SearchErrorの可能性があるかどうかを確認してください。たとえば、デバイスがオフラインの場合、検索アイテムのリストはnilになり、エラー列挙型 (enum) が原因を示します。この場合、ヘルパーメソッドshowDialog()を呼び出して、エラーの説明をユーザーに表示します。showDialog()の実装例には、付属の「検索」サンプルのソースコードからアクセスできます。これにはHERE SDK固有のコードは含まれません。

エラーが発生した場合は事前に除外するため、検索アイテムのリストを安全にアンラップできます。

検索のレスポンスにエラーまたは結果が含まれています。erroritems は一度に nil にすることや、一度に nil 以外にすることはできません。

結果を地図に表示する

それでは結果を見てみましょう。一致する結果が見つからなかった場合は、事前にエラーが検出されているはずです。

// If error is nil, it is guaranteed that the items will not be nil.
showDialog(title: "Search in viewport for: 'Pizza'.",
           message: "Found  \(items!.count) results.")

// Add a new marker for each search result on map.
for searchResult in items! {
    let metadata = Metadata()
    metadata.setCustomValue(key: "key_search_result", value: SearchResultMetadata(searchResult))
    // Note that geoCoordinates are always set, but can be nil for suggestions only.
    addPoiMapMarker(geoCoordinates: searchResult.geoCoordinates!, metadata: metadata)
}

...

// Class to store search results as Metadata.
private class SearchResultMetadata : CustomMetadataValue {

    var searchResult: Place

    init(_ searchResult: Place) {
        self.searchResult = searchResult
    }

    func getTag() -> String {
        return "SearchResult Metadata"
    }
}

最後に、結果のリストを反復処理します。各 Place には、見つかった検索結果を説明するさまざまなフィールドが含まれています。

この例では、地図にマーカーを追加するために、その場所の位置情報が重要になります。さらに、SearchResultを保存できるMetadataオブジェクトを作成します。

Metadataオブジェクトにはさまざまなデータタイプを含めることができ、マップマーカーと結果データを簡単に関連付けることができます。このようにして、マップマーカーに関連するすべての情報を1つのオブジェクトに格納できます。これは、たとえばユーザーがマップマーカーをタップした後など、このデータを表示するときに便利です。複雑なデータ オブジェクトでも、上に示したように CustomMetadataValue インターフェースを実装することで保存できます。

addPoiMapMarker()の実装例には、付属の「検索」サンプルのソースコードからアクセスできます。このガイドのマップマーカーに関するセクションも参照してください。

private func addPoiMapMarker(geoCoordinates: GeoCoordinates, metadata: Metadata) {
    let mapMarker = createPoiMapMarker(geoCoordinates: geoCoordinates)
    mapMarker.metadata = metadata
    mapView.mapScene.addMapMarker(mapMarker)
    mapMarkers.append(mapMarker)
}

private func createPoiMapMarker(geoCoordinates: GeoCoordinates) -> MapMarker {
    guard
        let image = UIImage(named: "poi"),
        let imageData = image.pngData() else {
            fatalError("Error: Image not found.")
    }
    let mapMarker = MapMarker(at: geoCoordinates,
                              image: MapImage(pixelData: imageData,
                                              imageFormat: ImageFormat.png),
                              anchor: Anchor2D(horizontal: 0.5, vertical: 1))
    return mapMarker
}

選択したマップマーカーが用意できたら、前の手順で設定したMetadata情報を取得できます。

if let searchResultMetadata =
    topmostMapMarker.metadata?.getCustomValue(key: "key_search_result") as? SearchResultMetadata {

    let title = searchResultMetadata.searchResult.title
    let vicinity = searchResultMetadata.searchResult.address.addressText
    showDialog(title: "Picked Search Result",
               message: "Title: \(title), Vicinity: \(vicinity)")
    return
}

すべてのマップマーカーにMetadataが含まれるわけではありません。事前にMetadataを設定していない限り、getMetadata()はnilを返します。この例では、"key_search_result"に保存されているデータがnilでないかどうかを単純に確認するだけで、検索データが含まれていることがわかります。次に、目的のPlaceを格納するカスタムタイプSearchResultMetadataにダウンキャストできます。

使用可能なオプションのフィールドの概要全体については、「APIリファレンス」を参照してください。

Web画像にアクセスする

HERE SDKには、place.Details内にWebImageオブジェクトのリストが用意されており、各Placeを視覚的に確認できます。

ウェブ画像を使用した検索結果を強化化するには、TripAdvisorからリッチコンテンツを受け取るための有効な資格情報が必要です。アクセスをリクエストするには、HERE営業担当者にお問い合わせください。ライセンスがない場合、画像リストは空になります。

WebImageアクセスは以下の方法で有効にできます。

searchEngine.setCustomOption(name: "discover.show", value: "tripadvisor");

WebImageアクセスが有効になり、リッチコンテンツの有効な資格情報が設定されると、検索結果に画像が含まれるようになります。PlaceからWebImageにアクセスするには、以下の方法を使用します。

func handleWebImages(searchResult: Place) {
    let webImages = searchResult.details.images
    for webImage in webImages {
        print("WebImage found for place: \(searchResult.title.trimmingCharacters(in: .whitespaces)). Link: \(webImage.source.href)")
    }
}

ユーザーは、プラットフォーム固有のアプリ内ロジックを使用して、各href内のwebImage.Sourceにアクセスして画像を取得できます。たとえば、hrefリンクは、https://media-cdn.tripadvisor.com/media/photo-f/10/fb/d1/05/panorama.jpgのようになります。

場所にズームする

上記のコードは、GeoBox を使用して、表示されたマップ ビューポート内で直接検索を行うため、見つかった結果にズームする必要はありません。GeoBox の代わりに、CountryCode 値のリストを渡すことで、場所の周囲 (「自分の周囲を検索」)、GeoCircle 内、GeoCorridor 沿い、または国内を検索することもできます。サポートされているすべてのタイプについては、TextQuery.Area を参照してください。

検索エリアが表示されたマップ ビューポートと等しくない場合は、次のコードを使用して、GeoCoordinates のリストから GeoBox を作成することで結果を確認できます。GeoBox.containing(geoCoordinates: geoCoordinatesList) から GeoBox を取得します。

// Set null values to keep the default map orientation.
camera.lookAt(area: geoBox,
              orientation: GeoOrientationUpdate(bearing: nil, tilt: nil))

これにより、カメラが瞬時に動きます。必要に応じて、さまざまなアニメーション スタイルを適用して、カメラを目的のエリアに移動させることもできます。MapCamera セクションで、GitHub にある「CameraKeyframeTracks」サンプル アプリを確認してください。

追加のパディングを適用する場合は、追加パラメーターとして viewRectangle を受け入れるオーバーロードされた lookAt() メソッドを使用します。長方形は、GeoBox が表示されるマップ ビューを参照してピクセル単位で指定されることに注意してください。

let origin = Point2D(5, 5)
let sizeInPixels = Size2D(width: mapView.viewportSize.width - 10, height: mapView.viewportSize.height - 10)
let paddedViewRectangle = Rectangle2D(origin: origin, size: sizeInPixels)

上記のコードは、マップ ビューポートに表示される GeoBox の周囲に 5 ピクセルのパディングを追加するために使用できる長方形を作成します。

Search サンプル アプリを試す

上のセクションと次のセクションの完全なコードは、GitHubSearchサンプルアプリに含まれています。

what3wordsを検索する (Navigateでのみ使用可能)

what3wordsは、地球上の3メートル四方の区画に3語の固有の住所を割り当てるジオコーディングシステムです。覚えやすい単語の組み合わせによって正確な場所を識別でき、これらの住所を正確な地理座標に変換することもできます。

例を見てみましょう。新しいW3WSearchEngineインスタンスを次のように作成できます。

do {
    try w3wSearchEngine = W3WSearchEngine()
} catch let engineInstantiationError {
    fatalError("Failed to initialize W3WSearchEngine. Cause: \(engineInstantiationError)")
}

新しいW3WSearchEngineインスタンスを作成すると、エラーがスローされる可能性があります。このようなエラーは、たとえば、HERE SDKの初期化が事前に失敗していた場合に発生する可能性があります。

W3WSearchEngineのサンプルコードは、GitHubの「SearchHybrid」サンプルアプリに含まれています。

指定されたwhat3words用語の場所を検索する (Navigateでのみ使用可能)

まず、searchWordsを設定します。次に、w3wSearchEngineの検索メソッドを呼び出し、用語を指定します。

検索が完了すると、コールバックは結果を処理します。

// Sample "dizzy.vanilla.singer" used for demonstration purposes. Replace with user input as needed.
let searchWords = "dizzy.vanilla.singer"

/* Finds the location of a known What3Words term.
* This method searches for the geographic location corresponding to a given three-word address
* (e.g., "dizzy.vanilla.singer"). It uses the What3Words API to resolve the three-word address into
* a square on the map, retrieving additional details such as the square's coordinates and language.
*/
w3wSearchEngine.search(words: searchWords) { [weak self] error, W3WSquare in
    guard let self = self else { return }
    if let error = error {
        self.showDialog(title: "W3W Search Error", message: "\(error)")
        return
    } else if let w3wSquare = W3WSquare {
        let message = """
            3-word address: \(w3wSquare.words)
            Language: \(w3wSquare.languageCode)
            Coordinates: \(w3wSquare.coordinates.latitude), \(w3wSquare.coordinates.longitude)
        """
        self.showDialog(title: "What3Words Details", message: message)
    }
}

what3words用語を場所にジオコード化する (Navigateでのみ使用可能)

指定された緯度と経度の値と、指定された言語コードを使って、まず、GeoCoordinatesオブジェクトを初期化します。次に、w3wSearchEngineの検索メソッドを呼び出し、座標、言語、レスポンスを管理するためのコールバックを指定します。

ジオコーディング検索が完了すると、コールバックは結果を処理します。

let coordinates = GeoCoordinates(latitude: 52.520798, longitude: 13.409408)
// The language code for the desired three-word address.
// ISO 639-1 code "en" specifies that the three-word address will be in English.

let w3wLanguageCode = "en";
/* Resolves geographic coordinates to a What3Words address (three-word format).
* This method uses the What3Words search engine to find a three-word address based
* on the provided coordinates (latitude and longitude). The result includes
* additional details such as the square's coordinates and language.
*/
w3wSearchEngine.search(coordinates: coordinates, language: w3wLanguageCode) { [weak self] error, W3WSquare in
    guard let self = self else { return }

    if let error = error {
        self.showDialog(title: "W3W reverse geocoding failed with error:", message: "\(error)")
        return
    } else if let w3wSquare = W3WSquare {
        let message = """
            3-word address: \(w3wSquare.words)
            Language: \(w3wSquare.languageCode)
            Coordinates: \(w3wSquare.coordinates.latitude), \(w3wSquare.coordinates.longitude)
        """
        self.showDialog(title: "Geocoding Details", message: message)
    } else {
        print("W3W reverse geocoding returned no results.")
        self.showDialog(title: "No Result", message: "W3W reverse geocoding returned no results.")
    }
}

EN 日本語

HERE documentation

Find answers to your product and technical questions

Documentation

What's new

Videos

EN 日本語

HERE ドキュメント

製品や技術に関する質問の答えを見つけましょう。より多くの内容と最新の情報については、英語版をご覧ください。

ドキュメント

ダイナミックマップ

動的コンテンツ関連のAPIをアプリやサービスに活用して、ドライバーが安全・快適かつ予定どおりに目的地へ到着できるよう支援します。

地図とデータ

世界中を走行する多数のマッピング車両から得られる最新の位置情報データを活用し、精度の高い地図やカスタムレイヤーを構築できます。

最新情報

動画

(function () { const input = document.querySelector('input[data-typeahead]'); if (!input) return; // Prevent the form from submitting/navigating input.closest('form')?.addEventListener('submit', e => e.preventDefault()); input.addEventListener('input', function () { const q = this.value.trim().toLowerCase(); document.querySelectorAll('.nav-group-name').forEach(group => { let anyVisible = false; group.querySelectorAll('.nav-group-task').forEach(task => { const text = task.textContent.trim().toLowerCase(); const show = !q || text.includes(q); task.style.display = show ? '' : 'none'; if (show) anyVisible = true; }); // Hide the whole group header if nothing matches group.style.display = anyVisible || !q ? '' : 'none'; }); }); })(); (function () { function onTokenClick(event) { var link = event.target.closest('.sdk-for-ios .item .token'); if (!link) return; event.preventDefault(); console.log('token clicked', link.textContent.trim()); var item = link.closest('.item'); if (!item) return; var content = item.querySelector('.height-container'); if (!content) { console.log('no .height-container found for item', item); return; } var isHidden = window.getComputedStyle(content).display === 'none'; content.style.display = isHidden ? 'block' : 'none'; link.classList.toggle('token-open', isHidden); var href = link.getAttribute('href'); if (href) { if (history.pushState) history.pushState({}, '', href); else location.hash = href; } } function openHashTarget() { var hash = window.location.hash.slice(1); if (!hash) return; var anchor = document.querySelector('.sdk-for-ios a[name="' + hash + '"]'); if (!anchor) return; var item = anchor.closest('.item'); if (!item) return; var link = item.querySelector('.token'); var content = item.querySelector('.height-container'); if (!link || !content) return; content.style.display = 'block'; link.classList.add('token-open'); } function init() { console.log('HERE SDK accordion init'); openHashTarget(); } document.removeEventListener('click', onTokenClick); document.addEventListener('click', onTokenClick); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } window.addEventListener('hashchange', openHashTarget); window.addEventListener('pageLoad', init); })();