搜尋文件

事前準備

如要將範例文件匯入 Document AI 倉儲,請參閱快速入門指南

定義文件結構定義和建立文件時,請務必考量要定義哪些屬性,以及這些屬性是否會用於搜尋。

如要使用屬性納入或排除部分文件以供搜尋,請將該屬性標示為可篩選。舉例來說,您可能會將代表「供應商」的屬性設為可篩選,因為使用者想搜尋特定供應商的月結單。

如要在資源上建構直方圖 (請參閱本主題後續範例),資源必須可供篩選。

如果屬性含有使用者在關鍵字搜尋期間會查詢的資料,請將該屬性標示為可搜尋。

全文搜尋是指在可搜尋文字中,擷取所有符合搜尋關鍵字的文件。使用者提供關鍵字清單 (以半形空格分隔的字詞),可能是輸入到 UI 的搜尋欄位中。在 Document AI 倉儲中,系統會處理關鍵字並轉換為適當的查詢。這類處理程序會去除停用字 (例如「the」、「in」和「an」),並將其餘字詞詞幹化。詞幹提取會將字詞縮減為常見版本,以便比對字詞變化。例如「work」、「working」、「worked」。

系統會搜尋哪些資料?

  • 文件的 plain_text
  • 如果匯入的是 Document AI 物件,請使用內嵌的 cloud_ai_document.text
  • 文件的 display_name。
  • 所有可搜尋的屬性。

查詢部分支援 Google AIP 樣式語法。具體來說,查詢支援字面值、邏輯運算子、否定運算子、比較運算子和函式。

  • 字面值:裸露的字面值 (例如「42」、「Hugo」) 是要比對的值。這項功能會搜尋文件的全文和可搜尋的屬性。
  • 邏輯運算子:「AND」、「and」、「OR」和「or」是二進位邏輯運算子 (例如:「engineer OR developer」)。
  • 否定運算子:「NOT」和「!」是否定運算子 (例如:「NOT 軟體」)。
  • 比較運算子:支援字串、數值、列舉、布林值的二元比較運算子 =!=<><=>=。也支援字串的 like 運算子 ~~。這項功能會剖析、詞幹化及擴充輸入查詢的同義字,提供語意搜尋功能。

    如要在查詢中指定屬性,比較運算式左側必須是屬性 ID (包括父項)。右側必須是常值。舉例來說,\"projects/123/locations/us\".property_a < 1 會比對專案 123us 位置中 property_a 小於 1 的結果。您可以在單一查詢中連結常值和比較運算式 (例如:software engineer \"projects/123/locations/us\".salary > 100)。

  • 函式:支援的函式有 LOWER([property_name])EMPTY([property_name]),前者執行比對時不會區分大小寫,後者用於篩選索引鍵是否存在。

  • 支援使用括號和邏輯運算子連結的巢狀運算式。如果運算式之間沒有運算子,預設邏輯運算子為 AND

這項查詢可搭配其他篩選器使用,例如 time_filtersfolder_name_filter。這些運算子會在幕後與 AND 運算子連線。

您可以依據 propertytimeschemafoldercreator 等其他參數,篩選搜尋查詢。

呼叫搜尋要求

如要呼叫搜尋服務,您必須使用搜尋要求,定義如下:

{
  "requestMetadata": {
    object (RequestMetadata)
  },
  "documentQuery": {
    object (DocumentQuery)
  },
  "offset": integer,
  "pageSize": integer,
  "pageToken": string,
  "orderBy": string,
  "histogramQueries": [
    {
      object (HistogramQuery)
    }
  ],
  "requireTotalSize": boolean,
  "totalResultSize": enum (TotalResultSize),
  "qaSizeLimit": integer
}

parent 欄位必須填入以下格式:

/projects/PROJECT_ID/locations/LOCATION

搜尋要求的回應

搜尋回應的定義如下:

{
  "matchingDocuments": [
    {
      object (MatchingDocument)
    }
  ],
  "nextPageToken": string,
  "totalSize": integer,
  "metadata": {
    object (ResponseMetadata)
  },
  "histogramQueryResults": [
    {
      object (HistogramQueryResult)
    }
  ]
}

文件查詢

document_query 欄位的定義如下:

{
  "query": string,
  "isNlQuery": boolean,
  "customPropertyFilter": string,
  "timeFilters": [
    {
      object (TimeFilter)
    }
  ],
  "documentSchemaNames": [
    string
  ],
  "propertyFilter": [
    {
      object (PropertyFilter)
    }
  ],
  "fileTypeFilter": {
    object (FileTypeFilter)
  },
  "folderNameFilter": string,
  "queryContext": [
    string
  ],
  "documentCreatorFilter": [
    string
  ],
  "customWeightsMetadata": {
    object (CustomWeightsMetadata)
  }
}

query」欄位是要求使用者搜尋查詢字詞。通常來自使用者介面的搜尋欄位。

篩選器

Document AI 倉儲提供多種篩選器。

文件時間篩選器

建立和更新時間篩選器可找出在指定時間範圍內,與關鍵字相符的文件。

TimeFilter 物件用於指定時間範圍,定義如下:

{
  "timeRange": {
    object (Interval)
  },
  "timeField": enum (TimeField)
}

您可以在 time_field 欄位中指定 time_range 中指定的時間範圍,是文件的建立時間還是上次更新時間。

time_range 欄位會將時間範圍指定為 IntervalInterval 的定義如下:

{
  "startTime": string,
  "endTime": string
}

創作者篩選器

如要搜尋特定使用者建立的文件,請使用建立者篩選器。例如:

  {
    document_query {
      query: "videogames director",
      documentCreatorFilter: [
        "diane@some_company.com",
        "frank@some_company.com",
      ],
    },
  }

屬性篩選器

只要屬性已設為可篩選,您就能使用屬性篩選器,針對結構定義中指定的任何屬性設定篩選器。

舉例來說,法律產業可使用屬性篩選器,依名為 COURT 的屬性篩選,只搜尋特定法院的文件。

屬性篩選器會使用 PropertyFilter 物件。您可以設定多個屬性篩選條件。使用多個屬性篩選器時,系統會使用 OR 運算子合併篩選器。 屬性篩選條件的定義如下:

  {
    "documentSchemaName": string,
    "condition": string
  }

屬性是在結構定義中定義。因此,您可以在 documentSchemaName 欄位中,指定用於篩選的屬性結構定義。在 condition 欄位中,您可以指定所需的邏輯。如需使用 documentSchemaNamecondition 欄位的範例,請參閱本頁面先前的範例。

相符文件

相符文件包含 Document 和程式碼片段 (稍後會討論)。MatchingDocument 中傳回的文件並非完整填寫的文件。其中包含的資料量最少,僅供向提出要求的使用者顯示搜尋結果清單。如果需要完整文件 (例如使用者點選搜尋結果),則應透過 GetDocument API 擷取完整文件。

填入下列 Document 欄位:Project numberDocument idDocument schema idCreate timeUpdate timeDisplay nameRaw document file typeReference idFilterable properties

相符的文件如下所示:

{
  "document": {
    object (Document)
  },
  "searchTextSnippet": string,
  "qaResult": {
    object (QAResult)
  }
}
的完整參考資料,

排名/排序

搜尋要求可讓您指定結果的排序方式。如要排序,請在搜尋要求中使用 order_by 欄位。這個欄位的可能值包括:

  • relevance desc - 關聯性遞減,也就是最符合的結果會顯示在最上方。
  • upload_date desc - 文件建立日期 (遞減排序,最新文件排在最上方)。
  • upload_date - 依文件建立日期遞增排序 (最舊的在最上方)。
  • update_date desc - 文件上次更新日期 (由新到舊排序)。
  • Update_date - 文件上次更新日期 (遞增排序,最舊的在最上方)。

如果您未指定排序方式,但提供搜尋關鍵字,系統會依相關性遞減排序 (最相符的結果會顯示在最上方)。如果未提供排序或關鍵字,系統會預設依更新時間降序排序 (最新文件在最上方)。

分頁

分頁功能可向使用者顯示一頁的資料。您可以在這裡指定網頁大小,並取得要向使用者顯示的結果大小總計 (例如「顯示 50 份文件,共 300 份」)。

page_size 欄位設為您希望搜尋要求傳回的結果數量。這可能符合 UI 搜尋結果顯示大小的規定。

這兩種機制分別是位移和網頁權杖。

偏移值是您要傳回的可退貨文件清單索引。舉例來說,偏移值為 5 表示您要從第六份文件開始。您可能會將偏移量增加頁面大小,以取得下一頁的結果。

或者,您也可以使用網頁權杖,不必擔心計算下一個偏移。提出第一個搜尋要求後,您會收到含有 next_page_token 欄位的搜尋回應。如果這個欄位留空,表示沒有其他結果。如果這個欄位不是空白,請設定 page_token 欄位,在下一個搜尋要求中使用這個權杖。

部分使用者介面會顯示搜尋到的文件數量。例如 you are viewing 10 documents of 120。如要取得傳回的文件計數,請將要求的 require_total_size boolean 欄位設為 True。 提示:require_total_size=True 會導致成效受到影響。在第一頁查詢中設定此值,然後在所有後續要求中將此值設為 false,並將總計數保留在區域變數中。

程式碼範例

Python

詳情請參閱 Document AI Warehouse Python API 參考文件

如要向 Document AI Warehouse 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。


from google.cloud import contentwarehouse

# TODO(developer): Uncomment these variables before running the sample.
# project_number = 'YOUR_PROJECT_NUMBER'
# location = 'YOUR_PROJECT_LOCATION' # Format is 'us' or 'eu'
# document_query_text = 'YOUR_DOCUMENT_QUERY'
# user_id = 'user:YOUR_SERVICE_ACCOUNT_ID' # Format is "user:xxxx@example.com"


def search_documents_sample(
    project_number: str, location: str, document_query_text: str, user_id: str
) -> None:
    # Create a client
    client = contentwarehouse.DocumentServiceClient()

    # The full resource name of the location, e.g.:
    # projects/{project_number}/locations/{location}
    parent = client.common_location_path(project=project_number, location=location)

    # File Type Filter
    # Options: DOCUMENT, FOLDER
    file_type_filter = contentwarehouse.FileTypeFilter(
        file_type=contentwarehouse.FileTypeFilter.FileType.DOCUMENT
    )

    # Document Text Query
    document_query = contentwarehouse.DocumentQuery(
        query=document_query_text,
        file_type_filter=file_type_filter,
    )

    # Histogram Query
    histogram_query = contentwarehouse.HistogramQuery(
        histogram_query='count("DocumentSchemaId")'
    )

    request_metadata = contentwarehouse.RequestMetadata(
        user_info=contentwarehouse.UserInfo(id=user_id)
    )

    # Define request
    request = contentwarehouse.SearchDocumentsRequest(
        parent=parent,
        request_metadata=request_metadata,
        document_query=document_query,
        histogram_queries=[histogram_query],
    )

    # Make the request
    response = client.search_documents(request=request)

    # Print search results
    for matching_document in response.matching_documents:
        document = matching_document.document
        # Display name - schema display name.
        # Name.
        # Create date.
        # Snippet - keywords are highlighted with <b> & </b>.
        print(
            f"{document.display_name} - {document.document_schema_name}\n"
            f"{document.name}\n"
            f"{document.create_time}\n"
            f"{matching_document.search_text_snippet}\n"
        )

    # Print histogram
    for histogram_query_result in response.histogram_query_results:
        print(
            f"Histogram Query: {histogram_query_result.histogram_query}\n"
            f"| {'Schema':<70} | {'Count':<15} |"
        )
        for key, value in histogram_query_result.histogram.items():
            print(f"| {key:<70} | {value:<15} |")

Java

詳情請參閱 Document AI Warehouse Java API 參考文件

如要向 Document AI Warehouse 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。

import com.google.cloud.contentwarehouse.v1.DocumentQuery;
import com.google.cloud.contentwarehouse.v1.DocumentServiceClient;
import com.google.cloud.contentwarehouse.v1.DocumentServiceClient.SearchDocumentsPagedResponse;
import com.google.cloud.contentwarehouse.v1.DocumentServiceSettings;
import com.google.cloud.contentwarehouse.v1.FileTypeFilter;
import com.google.cloud.contentwarehouse.v1.FileTypeFilter.FileType;
import com.google.cloud.contentwarehouse.v1.LocationName;
import com.google.cloud.contentwarehouse.v1.RequestMetadata;
import com.google.cloud.contentwarehouse.v1.SearchDocumentsRequest;
import com.google.cloud.contentwarehouse.v1.SearchDocumentsResponse.MatchingDocument;
import com.google.cloud.contentwarehouse.v1.UserInfo;
import com.google.cloud.resourcemanager.v3.Project;
import com.google.cloud.resourcemanager.v3.ProjectName;
import com.google.cloud.resourcemanager.v3.ProjectsClient;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

public class SearchDocuments {
  public static void main(String[] args) throws IOException, 
        InterruptedException, ExecutionException, TimeoutException { 
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "your-project-id";
    String location = "your-region"; // Format is "us" or "eu".
    String documentQuery = "your-document-query";
    String userId = "your-user-id"; // Format is user:<user-id>

    searchDocuments(projectId, location, documentQuery, userId);
  }

  // Searches all documents for a given Document Query
  public static void searchDocuments(String projectId, String location,
        String documentQuery, String userId) throws IOException, InterruptedException,
          ExecutionException, TimeoutException { 
    String projectNumber = getProjectNumber(projectId);

    String endpoint = "contentwarehouse.googleapis.com:443";
    if (!"us".equals(location)) {
      endpoint = String.format("%s-%s", location, endpoint);
    }

    DocumentServiceSettings documentServiceSettings = 
             DocumentServiceSettings.newBuilder().setEndpoint(endpoint)
             .build(); 

    /*
     * Create the Document Service Client 
     * Initialize client that will be used to send requests. 
     * This client only needs to be created once, and can be reused for multiple requests. 
     */
    try (DocumentServiceClient documentServiceClient = 
            DocumentServiceClient.create(documentServiceSettings)) {  

      /*
       * The full resource name of the location, e.g.:
       * projects/{project_number}/locations/{location} 
       */
      String parent = LocationName.format(projectNumber, location);

      // Define RequestMetadata object for context of the user making the API call
      RequestMetadata requestMetadata = RequestMetadata.newBuilder()
          .setUserInfo(
          UserInfo.newBuilder()
            .setId(userId)
            .build())
            .build();

      // Set file type for filter to 'DOCUMENT'
      FileType documentFileType = FileType.DOCUMENT;

      // Create a file type filter for documents 
      FileTypeFilter fileTypeFilter = FileTypeFilter.newBuilder()
          .setFileType(documentFileType)
          .build();

      // Create document query to search all documents for text given at input
      DocumentQuery query = DocumentQuery.newBuilder()
          .setQuery(documentQuery)
          .setFileTypeFilter(fileTypeFilter)
          .build();

      /*
       * Create the request to search all documents for specified query. 
       * Please note the offset in this request is to only return the specified number of results 
       * to avoid hitting the API quota. 
       */
      SearchDocumentsRequest searchDocumentsRequest = SearchDocumentsRequest.newBuilder()
          .setParent(parent)
          .setRequestMetadata(requestMetadata)
          .setOffset(5)
          .setDocumentQuery(query)
          .build();

      // Make the call to search documents with document service client and store the response
      SearchDocumentsPagedResponse searchDocumentsPagedResponse = 
          documentServiceClient.searchDocuments(searchDocumentsRequest);

      // Iterate through response and print search results for documents matching the search query
      for (MatchingDocument matchingDocument :
          searchDocumentsPagedResponse.iterateAll()) {
        System.out.println(
            "Display Name: " + matchingDocument.getDocument().getDisplayName()
            + "Document Name: " + matchingDocument.getDocument().getName()
            + "Document Creation Time: " + matchingDocument.getDocument().getCreateTime().toString()
            + "Search Text Snippet: " + matchingDocument.getSearchTextSnippet());
      }
    }
  }

  private static String getProjectNumber(String projectId) throws IOException { 
    /*
     * Initialize client that will be used to send requests. 
     * This client only needs to be created once, and can be reused for multiple requests.
     */
    try (ProjectsClient projectsClient = ProjectsClient.create()) { 
      ProjectName projectName = ProjectName.of(projectId); 
      Project project = projectsClient.getProject(projectName);
      String projectNumber = project.getName(); // Format returned is projects/xxxxxx
      return projectNumber.substring(projectNumber.lastIndexOf("/") + 1);
    } 
  }
}

後續步驟