建立及註冊結構定義

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

Google Cloud Search 結構定義是 JSON 結構,可定義要在索引和查詢資料中使用的物件、屬性和選項。 內容連接器會從您的存放區讀取資料,並根據已註冊的結構定義建立資料結構和建立索引。

只要將 JSON 結構定義物件提供給 API 並加以註冊,即可建立結構定義。您必須為各個存放區註冊一個結構定義物件,才能為資料建立索引。

本文件涵蓋建立結構定義的基本概念。如要瞭解如何調整結構定義以改善搜尋體驗,請參閱改善搜尋品質

建立結構定義

以下是建立 Cloud Search 結構定義的步驟清單:

  1. 識別使用者預期的行為
  2. 初始化資料來源
  3. 建立結構定義
  4. 完整的範例結構定義
  5. 註冊結構定義
  6. 為資料建立索引
  7. 測試結構定義
  8. 調整結構定義

識別使用者預期的行為

預測使用者進行的查詢類型,有助於擬定結構定義。

例如,對電影資料庫發出查詢時,您可能會預期使用者所做的查詢會如「顯示由 Robert Redford 主演的所有電影」之類的查詢內容。因此,您的結構定義必須支援依據「指定具備特定演員的所有電影」來提供查詢結果。

如要定義結構定義以反映使用者的行為模式,請考慮執行以下工作:

  1. 評估不同使用者期望的各式查詢。
  2. 找出可用於查詢的物件。物件是相關資料的邏輯組合,例如電影資料庫中的電影。
  3. 找出組成物件並可用於查詢的屬性和值。 「屬性」是物件的可建立索引屬性;屬性可包含原始值或其他物件。例如,電影物件可能會以電影標題和推出日期等屬性做為原始值。電影物件也可以包含其他具有其屬性的物件,例如姓名或角色。
  4. 識別屬性的有效值範例。「值」是為資源實際建立索引的資料。例如,資料庫中某部電影的標題可能是「失落方格的攻略」。
  5. 決定使用者需要的排序和排序選項。例如,查詢電影時,使用者可能會依照時間順序排序,並依目標對象分級來排序,因此不需要按字母順序排列。
  6. (選用) 請考慮您的其中一項屬性代表可能執行搜尋的具體背景資訊,例如使用者的職缺或部門,以便系統根據情境提供自動完成建議。例如,對於搜尋電影資料庫的使用者,使用者可能只想對特定類型的電影感興趣。使用者會定義想要傳回的內容類型,可能是使用者設定檔的一部分。這樣一來,當使用者開始輸入電影查詢時,系統只會建議使用者偏好的類型 (例如「動作片」) 中的電影做為自動完成建議的一部分。
  7. 列出可用於搜尋的物件、屬性和範例值。(如要進一步瞭解這個清單的使用方式,請參閱「定義運算子選項」一節)。

初始化資料來源

「資料來源」代表來自已建立索引並儲存在 Google Cloud 的存放區中的資料。如需初始化資料來源的操作說明,請參閱管理第三方資料來源一文。

使用者的搜尋結果會傳回資料來源。當使用者點選搜尋結果時,Cloud Search 會使用建立索引要求中提供的網址,將使用者導向實際項目。

定義物件

結構定義的基本資料單位為「物件」,也稱為「結構定義物件」,即邏輯的資料結構。電影資料庫的邏輯結構為「電影」。另一個物件可能是「人物」來代表與這部電影相關的演員和工作人員。

結構定義中的每個物件都有一系列用於說明物件的屬性或屬性,例如電影的名稱和時間長度,或某人的姓名和出生日期。物件的屬性可包含原始值或其他物件。

圖 1 顯示電影和人物物件以及相關屬性。

實體之間的結構定義連線圖
圖 1. 顯示兩個物件和子物件的範例結構定義。

Cloud Search 結構定義基本上是在 objectDefinitions 標記中定義的物件定義陳述式清單。以下結構定義程式碼片段顯示電影和人物結構定義物件的 objectDefinitions 陳述式。

{
  "objectDefinitions": [
    {
      "name": "movie",
      ...
    },
    {
      "name": "person",
      ...
    }
  ]
}

定義結構定義物件時,您必須提供 name 物件,且該物件在結構定義的所有其他物件中不得重複。您通常會使用說明物件的 name 值,例如用於電影物件的 movie。結構定義服務會使用 name 欄位做為可建立索引物件的索引鍵 ID。如要進一步瞭解 name 欄位,請參閱物件定義

定義物件屬性

ObjectDefinition 的參照所示,物件名稱後面接著一組 optionspropertyDefinitions 清單。options 可以進一步包含 freshnessOptionsdisplayOptionsfreshnessOptions 會根據項目的時效性來調整搜尋排名。displayOptions 是用於定義是否要在物件搜尋結果中顯示特定標籤和屬性。

propertyDefinitions 區段可讓您定義物件的屬性,例如電影標題和發布日期。

下列程式碼片段顯示包含兩個屬性的 movie 物件:movieTitlereleaseDate

{
  "objectDefinitions": [
    {
      "name": "movie",
      "propertyDefinitions": [
        {
          "name": "movieTitle",
          "isReturnable": true,
          "isWildcardSearchable": true,
          "textPropertyOptions": {
            "retrievalImportance": { "importance": "HIGHEST" },
            "operatorOptions": {
              "operatorName": "title"
            }
          },
          "displayOptions": {
            "displayLabel": "Title"
          }
        },
        {
          "name": "releaseDate",
          "isReturnable": true,
          "isSortable": true,
          "datePropertyOptions": {
            "operatorOptions": {
              "operatorName": "released",
              "lessThanOperatorName": "releasedbefore",
              "greaterThanOperatorName": "releasedafter"
            }
          },
          "displayOptions": {
            "displayLabel": "Release date"
          }
      ...
      ]
    }
  ]
}

PropertyDefinition 包含下列項目:

  • name 字串。
  • 型別通用選項的清單,例如前一個程式碼片段中的 isReturnable
  • 類型及其相關聯的類型專屬選項,例如前一個程式碼片段中的 textPropertyOptionsretrievalImportance
  • 說明屬性如何做為搜尋運算子的 operatorOptions
  • 一或多個 displayOptions,例如前一個程式碼片段中的 displayLabel

屬性的 name 必須和所含物件相同,但其他物件和子物件可以使用相同的名稱。在圖 1 中,電影的標題和推出日期已定義兩次:一次在 movie 物件中,並在 person 物件的 filmography 子物件中再次定義。這個結構定義會重複使用 movieTitle 欄位,以便結構定義支援兩種搜尋行為:

  • 當使用者搜尋電影名稱時,系統會顯示電影搜尋結果
  • 當使用者搜尋演員演員電影的電影時,顯示人物搜尋結果

同樣地,結構定義會重複使用 releaseDate 欄位,因為這兩個 movieTitle 欄位的含義相同。

開發自己的結構定義時,請考慮存放區中可能包含的相關欄位,其中包含您要在結構定義中多次宣告的資料。

新增各類型選項

PropertyDefinition 列出了所有屬性的一般搜尋功能選項,無論資料類型為何。

  • isReturnable - 指出屬性是否應透過 Query API 傳回應傳回搜尋結果中的資料。所有範例電影屬性都可傳回。不可傳回的屬性可用於搜尋或排名結果,而不必傳回使用者。
  • isRepeatable - 指出該屬性是否允許多個值。例如,一部電影只有上映日期,但可以有多位演員。
  • isSortable - 表示該屬性可用於排序。針對可重複使用的屬性,則無法如此。例如,電影可以依照上映日期或觀眾評分排序。
  • isFacetable - 表示這個屬性可用於產生 商情項目。 商情項目可用來修正搜尋結果,使用者會看到初始結果,然後新增條件 (或商情項目) 來進一步修正這些結果。如果類型為物件且 isReturnable 必須設為 true,就無法設定此選項。最後,這個選項僅支援列舉、布林值和文字屬性。 例如,在範例結構定義中,我們可能會將 genreactorNameuserRatingmpaaRating 設為可臉孔,以便用於互動式的互動式搜尋結果。
  • isWildcardSearchable 表示使用者可以對這項屬性執行萬用字元搜尋。這個選項僅適用於文字屬性。萬用字元搜尋在文字欄位中的運作方式,取決於 exactMatchWithOperator 欄位設定的值。如果 exactMatchWithOperator 設為 true,文字值會權杖化為一個不可部分的值,並對其執行萬用字元搜尋。舉例來說,如果文字值為 science-fiction,則萬用字元查詢 science-* 會符合該文字。如果 exactMatchWithOperator 設為 false,文字值會權杖化,且系統會對每個符記執行萬用字元搜尋。舉例來說,如果文字值是「Science-科幻」,萬用字元查詢 sci*fi* 就會與該項目相符,但 science-* 並不相符。

這些一般搜尋功能參數都是布林值;它們的預設值為 false,且必須設為 true 才能使用。

下表顯示 movie 物件所有屬性設為 true 的布林值參數:

屬性 isReturnable isRepeatable isSortable isFacetable isWildcardSearchable
movieTitle
releaseDate
genre
duration
actorName
userRating
mpaaRating

genreactorName 都將 isRepeatable 設為 true,因為電影可能同時屬於多個類型,且通常具有多位演員。屬性不可重複,或包含可重複子物件。

定義類型

PropertyDefinition 參考資料區段會列出數個 xxPropertyOptions,其中 xx 是特定類型的,例如 boolean。如要設定屬性的資料類型,您必須定義適當的資料類型物件。為屬性定義資料類型物件時,系統會建立該屬性的資料類型。例如,在 movieTitle 屬性中定義 textPropertyOptions,代表電影標題屬於類型文字。以下程式碼片段顯示設定 textPropertyOptionsmovieTitle 屬性。

{
  "name": "movieTitle",
  "isReturnable": true,
  "isWildcardSearchable": true,
  "textPropertyOptions": {
    ...
  },
  ...
},

每項資源只能有一個關聯的資料類型。例如,在電影結構定義中,releaseDate 只能是日期 (例如2016-01-13) 或字串 (例如January 13, 2016),但只能擇一使用。

以下是用於指定電影結構定義中屬性資料類型的資料類型:

屬性 資料類型物件
movieTitle textPropertyOptions
releaseDate datePropertyOptions
genre enumPropertyOptions
duration textPropertyOptions
actorName textPropertyOptions
userRating integerPropertyOptions
mpaaRating textPropertyOptions

您為資源選擇的資料類型,取決於您的預期用途。在這種電影架構的想像情境中,使用者希望依時間先後排序結果,所以 releaseDate 是日期物件。例如,如果比較 12 月份的年份與 1 月版本的比較結果,則字串格式可能很實用。

設定特定類型選項

PropertyDefinition 參考資料區段會連結至各個類型的選項。除了 enumPropertyOptions 中的 possibleValues 清單以外,大多數類型專用的選項都是選用項目。此外,orderedRanking 選項可讓您決定不同值之間的排名。下列程式碼片段顯示 movieTitle 屬性,其中 textPropertyOptions 設定資料類型,使用 retrievalImportance 類型專屬選項。

{
  "name": "movieTitle",
  "isReturnable": true,
  "isWildcardSearchable": true,
  "textPropertyOptions": {
    "retrievalImportance": { "importance": "HIGHEST" },
    ...
  },
  ...
}

以下是範例結構定義中使用的其他特定類型選項:

屬性 類型 特定類型選項
movieTitle textPropertyOptions retrievalImportance
releaseDate datePropertyOptions
genre enumPropertyOptions
duration textPropertyOptions
actorName textPropertyOptions
userRating integerPropertyOptions maximumValueorderedRanking
mpaaRating textPropertyOptions

定義運算子選項

除了類型專用的選項之外,每種類型都有一組選用 operatorOptions 選項,用於說明屬性如何做為搜尋運算子使用。下列程式碼片段顯示 movieTitle 屬性,其中 textPropertyOptions 設定資料類型,以及 retrievalImportanceoperatorOptions 類型專屬選項。

{
  "name": "movieTitle",
  "isReturnable": true,
  "isWildcardSearchable": true,
  "textPropertyOptions": {
    "retrievalImportance": { "importance": "HIGHEST" },
    "operatorOptions": {
      "operatorName": "title"
    }
  },
  ...
}

每個 operatorOptions 都有 operatorName,例如 movieTitletitle。運算子名稱是屬性的搜尋運算子。搜尋運算子是指使用者縮小搜尋時要使用的實際參數。舉例來說,如要根據標題搜尋電影,使用者可以輸入 title:movieName,其中 movieName 就是電影名稱。

運算子名稱不必與屬性名稱相同。請改用運算子名稱,反映貴機構使用者最常使用的字詞。舉例來說,如果使用者偏好以「名稱」一詞取代電影的「名稱」,則運算子名稱應設為「名稱」。

只要所有屬性解析為相同的類型,您就可以針對多個屬性使用相同的運算子名稱。在查詢中使用共用運算子名稱時,系統會擷取使用該運算子名稱的所有屬性。例如,假設電影物件有 plotSummaryplotSynopsis 屬性,且每個屬性都有 operatorNameplot。只要這兩個屬性都是文字 (textPropertyOptions),則使用 plot 搜尋運算子的單一查詢會擷取這兩項屬性。

除了 operatorName 以外,可排序的屬性也可以在 operatorOptions 中加入 lessThanOperatorNamegreaterThanOperatorName 欄位。使用者可以透過這些選項,與提交值的比較建立查詢。

最後,textOperatorOptionsoperatorOptions 欄位含有 exactMatchWithOperator。如果將 exactMatchWithOperator 設為 true,查詢字串必須與整個屬性值相符,而不能只從文字中找到。在運算子搜尋和商情項目比對中,系統會將文字值視為一個不可部分的值。

舉例來說,您可以對具有類型屬性的「圖書」或「電影」物件建立索引。 類型可能包括「科學小說」、「科學」和「小說」。將 exactMatchWithOperator 設為 false 或省略時,搜尋某個類型或選取「科學」或「小說」商情項目也會傳回「Science-Fiction」的結果,因為文字已代碼化,而「Science」和「Fiction」憑證則存在於「Science-Fiction」。當 exactMatchWithOperatortrue 時,文字會視為單一符記,因此「Science」和「Fiction」都不符合「Science-Fiction」。

(選用) 新增 displayOptions 區段

任何 propertyDefinition 區段結尾都有選用的 displayOptions 區段。這個部分包含一個 displayLabel 字串。displayLabel 是建議屬性的好用文字標籤。如果設定使用 ObjectDisplayOptions 設定顯示屬性,這個標籤會顯示在屬性前面。如果屬性設定為顯示且未定義 displayLabel,則只會顯示屬性值。

下列程式碼片段顯示 displayLabel 屬性設為「Title」的 movieTitle 屬性。

{
  "name": "movieTitle",
  "isReturnable": true,
  "isWildcardSearchable": true,
  "textPropertyOptions": {
    "retrievalImportance": { "importance": "HIGHEST" },
    "operatorOptions": {
       "operatorName": "title"
    }
},
  "displayOptions": {
    "displayLabel": "Title"
  }
},

以下是範例結構定義中 movie 物件所有屬性的 displayLabel 值:

屬性 displayLabel
movieTitle Title
releaseDate Release date
genre Genre
duration Run length
actorName Actor
userRating Audience score
mpaaRating MPAA rating

(選用) 新增「suggestionFilteringOperators[]」版面

在任何 propertyDefinition 區段的結尾都有一個選用的 suggestionFilteringOperators[] 區段。在本節中,您可以定義用來篩選自動完成建議的屬性。例如,您可以定義 genre 的運算子,以根據使用者偏好的電影類型篩選建議。這樣一來,當使用者輸入搜尋查詢時,系統僅會在自動完成建議中顯示與所需類型相符的電影。

註冊結構定義

如要透過 Cloud Search 查詢傳回結構化資料,則必須向 Cloud Search 結構定義服務註冊結構定義。註冊結構定義時,需要使用您在初始化資料來源步驟中取得的資料來源 ID。

使用資料來源 ID 發出 UpdateSchema 要求,以註冊結構定義。

UpdateSchema 參考資料頁面所述,請發出以下的 HTTP 要求來註冊結構定義:

PUT https://cloudsearch.googleapis.com/v1/indexing/{name=datasources/*}/schema

您的要求內文應包含以下內容:

{
  "validateOnly": // true or false,
  "schema": {
    // ... Your complete schema object ...
  }
}

您可以使用 validateOnly 選項來測試結構定義是否有效,而不必實際註冊。

為資料建立索引

結構定義註冊完畢之後,請使用索引呼叫填入資料來源。一般來說,您可以透過內容連接器完成索引建立作業。

使用電影結構定義時,單一電影的 REST API 索引要求看起來會像這樣:

{
  "name": "datasource/<data_source_id>/items/titanic",
  "acl": {
    "readers": [
      {
        "gsuitePrincipal": {
          "gsuiteDomain": true
        }
      }
    ]
  },
  "metadata": {
    "title": "Titanic",
    "sourceRepositoryUrl": "http://www.imdb.com/title/tt2234155/?ref_=nv_sr_1",
    "objectType": "movie"
  },
  "structuredData": {
    "object": {
      "properties": [
        {
          "name": "movieTitle",
          "textValues": {
            "values": [
              "Titanic"
            ]
          }
        },
        {
          "name": "releaseDate",
          "dateValues": {
            "values": [
              {
                "year": 1997,
                "month": 12,
                "day": 19
              }
            ]
          }
        },
        {
          "name": "actorName",
          "textValues": {
            "values": [
              "Leonardo DiCaprio",
              "Kate Winslet",
              "Billy Zane"
            ]
          }
        },
        {
          "name": "genre",
          "enumValues": {
            "values": [
              "Drama",
              "Action"
            ]
          }
        },
        {
          "name": "userRating",
          "integerValues": {
            "values": [
              8
            ]
          }
        },
        {
          "name": "mpaaRating",
          "textValues": {
            "values": [
              "PG-13"
            ]
          }
        },
        {
          "name": "duration",
          "textValues": {
            "values": [
              "3 h 14 min"
            ]
          }
        }
      ]
    }
  },
  "content": {
    "inlineContent": "A seventeen-year-old aristocrat falls in love with a kind but poor artist aboard the luxurious, ill-fated R.M.S. Titanic.",
    "contentFormat": "TEXT"
  },
  "version": "01",
  "itemType": "CONTENT_ITEM"
}

請注意,objectType 欄位中的 movie 值與結構定義中的物件定義名稱相符。透過比對這兩個值,Cloud Search 會在建立索引時知道要使用哪個結構定義物件。

另請注意,結構定義屬性 releaseDate 的索引如何使用繼承的 yearmonthday 子屬性,因為其是透過 datePropertyOptions 定義為 date 資料類型。不過,由於結構定義中並未定義 yearmonthday,因此您無法查詢其中一項屬性 (例如:year)。

另請注意,如何使用值清單,為可重複屬性 actorName 建立索引。

找出潛在的索引問題

與結構定義和索引相關的兩個最常見的問題如下:

  • 您的索引要求含有尚未透過結構定義服務註冊的結構定義物件或屬性名稱。這個問題會忽略屬性或物件。

  • 您的索引要求具有類型與結構定義中登錄類型不同的屬性。這個問題會使 Cloud Search 在索引時傳回錯誤。

使用多種查詢類型來測試結構定義

在註冊大型實際工作環境資料存放區的結構定義之前,請考慮使用較小的測試資料存放區進行測試。透過較小的測試存放區進行測試,可讓您快速調整結構定義並刪除已建立索引的資料,而不會影響到更大的索引或現有的實際工作環境索引。針對測試資料存放區,請建立僅將測試使用者授權的 ACL,讓其他使用者無法在搜尋結果中看到這項資料。

如要建立搜尋介面以驗證搜尋查詢,請參閱搜尋介面

本節包含您可能用來測試電影結構定義的不同範例查詢。

使用一般查詢進行測試

一般查詢會傳回資料來源中包含特定字串的所有項目。使用搜尋介面時,您可以輸入「titanic」這個字詞並按下 Return 鍵,對電影資料來源執行一般查詢。所有具有「鐵」字的電影都應在搜尋結果中傳回。

使用運算子進行測試

在查詢中加入運算子,將結果限制為符合該運算子值的項目。例如,您可能想使用 actor 運算子來尋找由特定演員主演的所有電影。使用搜尋介面時,您只要輸入 operator=value 組合 (例如「actor:Zane"」),再按下 Return 鍵,即可執行這個運算子查詢。所有以 Zane 為演員的電影都應在搜尋結果中傳回。

調整結構定義

結構定義和資料使用完成之後,請繼續監控哪些方法有效,以及對使用者沒有作用。在下列情況下,請考慮調整結構定義:

  • 為先前未編入索引的欄位建立索引。例如,使用者可能會依據導演的名稱重複搜尋電影,因此您可以調整結構定義,以支援導演名稱做為運算子。
  • 根據使用者的意見變更搜尋運算子名稱。運算子名稱容易使用。如果您的使用者持續「記住」錯誤的運算子名稱,請考慮變更名稱。

在結構定義變更之後重新建立索引

在結構定義中變更以下任何值需要為您的資料重新建立索引。您只需提交新的 UpdateSchema 要求,索引就會繼續運作:

  • 運算子名稱。
  • 整數的最小值和最大值。
  • 按整數和列舉的排序排名。
  • 更新選項。
  • 顯示選項。

針對以下變更,先前建立索引的資料會繼續按照先前註冊的結構定義運作。但是,如果現有的項目有下列變更,您必須重新對現有項目重新建立索引,以根據更新後的結構定義查看變更:

  • 新增或移除新屬性或物件
  • 正在將 isReturnableisFacetableisSortablefalse 變更為 true

只有在明確有明確用途和需求時,才應將 isFacetableisSortable 設為 true

最後,當您為屬性 isSuggestable 標記屬性來更新結構定義時,您必須重新為資料建立索引,這樣會造成該屬性的自動完成功能出現延遲。

不允許的屬性變更

即使您為資料重新建立索引,也不允許某些結構定義變更,因為這會導致索引中斷,或是產生品質不佳或不一致的搜尋結果。其中包括:

  • 屬性資料類型。
  • 屬性名稱。
  • exactMatchWithOperator 設定。
  • retrievalImportance 設定。

但有幾種限制。

變更複雜的結構定義

為了避免造成搜尋結果不佳或搜尋索引毀損的情況發生,Cloud Search 會在存放區索引建立後,禁止某些類型的 UpdateSchema 要求變更。例如,屬性的資料類型或屬性名稱一經設定即無法變更。即使您對資料重新建立索引,也無法透過簡單的 UpdateSchema 要求完成這些變更。

如果您必須對結構定義另外進行「不允許」變更,則您通常可以進行一系列「允許」的變更,以達成相同的效果。一般來說,您必須先將已建立索引的屬性從舊的物件定義遷移至新版物件,再傳送僅使用新屬性的索引要求。

下列步驟將說明如何變更屬性的資料類型或名稱:

  1. 在結構定義中的物件定義新增屬性。請使用您要變更的屬性名稱。
  2. 使用新定義發出 UpdateSchema 要求。請記得在要求中傳送整個結構定義,包括新屬性。
  3. 從資料存放區補充索引。如要補充索引,請使用新屬性 (而非「不」舊屬性) 傳送所有索引要求,因為這會導致重複計算查詢。

    1. 建立索引時,請檢查新屬性並預設為舊屬性,以避免行為不一致。
    2. 完成補充作業之後,請執行測試查詢進行驗證。
  4. 刪除舊資源。再次發出沒有舊屬性名稱的另一個 UpdateSchema 要求,並在日後停止建立索引的要求中繼續使用舊屬性名稱。

  5. 將舊資源的所有使用情形遷移到新資源。例如,如果您將屬性名稱從「creator」改為「author」;您必須更新查詢程式碼,才能使用先前參照該建立者的作者。

Cloud Search 會將已刪除屬性或物件的記錄保留 30 天,以免發生任何可能導致非預期索引結果的重複使用。在該 30 天內,請不要遷移已刪除物件或屬性的所有用量,包括在日後提出的索引要求中省略這些物件或屬性。這可以確保之後決定恢復該屬性或物件後,能夠維持索引的正確性。

瞭解大小限制

Cloud Search 對結構化資料物件和結構定義的大小設有限制。這些限制包括:

  • 頂層物件的數量上限為 10 個物件。
  • 結構化資料階層的深度上限為 10 層。
  • 物件中的欄位總數上限為 1000 個,其中包括原始欄位的數量加上每個巢狀物件中的欄位總數。

後續步驟

建議您採取下列步驟:

  1. 建立搜尋介面來測試結構定義。

  2. 調整結構定義以改善搜尋品質

  3. 建構出最佳查詢解譯的結構定義

  4. 瞭解如何利用 _dictionaryEntry 結構定義,定義貴公司常用字詞的同義詞。如要使用 _dictionaryEntry 結構定義,請參閱定義同義詞

  5. 建立連接器