Cercare documenti

Prima di iniziare

Per importare documenti di esempio in Document AI Warehouse, consulta la guida rapida.

Quando definisci gli schemi dei documenti e crei i documenti, è importante considerare quali proprietà vuoi definire e come verranno utilizzate con la ricerca, se verranno utilizzate.

Contrassegna una proprietà come filtrabile se vuoi utilizzarla per includere o escludere una parte dei documenti per una ricerca. Ad esempio, potresti rendere filtrabile una proprietà che rappresenta un "Fornitore" perché gli utenti vogliono cercare le fatture di un fornitore specifico.

Se vuoi creare un istogramma (vedi l'esempio più avanti in questo argomento) per una proprietà, questa deve essere filtrabile.

Contrassegna una proprietà come ricercabile se contiene dati che gli utenti vorranno interrogare durante una ricerca di parole chiave.

La ricerca a testo intero è il processo di recupero di tutti i documenti che corrispondono alle parole chiave di ricerca nel testo ricercabile. L'utente fornisce un elenco di parole chiave (parole separate da uno spazio vuoto), presumibilmente digitate in un campo di ricerca nell'interfaccia utente. In Document AI Warehouse, le parole chiave vengono elaborate e convertite in una query appropriata. Questa elaborazione elimina le stopword ("il", "in" e "un") e riduce le parole rimanenti al tema. Lo stemming riduce la parola a una versione comune della formulazione, in modo che la variazione della parola corrisponda. Ad esempio: "lavoro", "lavorando", "lavorato".

Quali dati vengono inclusi nella ricerca?

  • plain_text del documento.
  • Se importi un oggetto Document AI, utilizza cloud_ai_document.text incorporato.
  • Il nome visualizzato del documento.
  • Tutte le proprietà disponibili per la ricerca.

La query supporta parzialmente la sintassi di stile Google AIP. Nello specifico, la query supporta valori letterali, operatori logici, operatori di negazione, operatori di confronto e funzioni.

  • Valori letterali: un valore letterale semplice (ad esempio "42", "Hugo") è un valore da confrontare. Esegue la ricerca nell'intero testo del documento e nelle proprietà ricercabili.
  • Operatori logici: "AND", "and", "OR" e "or" sono operatori logici binari (esempio: "engineer OR developer").
  • Operatori di negazione: "NOT" e "!" sono operatori di negazione (ad esempio: "NOT software").
  • Operatori di confronto: supportano gli operatori di confronto binario =, !=, <, >, <= e >= per stringhe, valori numerici, enumerazioni e valori booleani. Supporta anche l'operatore ~~ per le stringhe. Fornisce la funzionalità di ricerca semantica analizzando, estraendo i temi e ampliando i sinonimi in base alla query di input.

    Per specificare una proprietà nella query, l'espressione a sinistra nel confronto deve essere l'ID proprietà, incluso il genitore. Il lato destro deve contenere valori letterali. Ad esempio: \"projects/123/locations/us\".property_a < 1 corrisponde ai risultati il cui property_a è inferiore a 1 nel progetto 123 e nella località us. I valori letterali e l'espressione di confronto possono essere collegati in una singola query (ad esempio, software engineer \"projects/123/locations/us\".salary > 100).

  • Funzioni: le funzioni supportate sono LOWER([property_name]) per eseguire una corrispondenza senza distinzione tra maiuscole e minuscole e EMPTY([property_name]) per filtrare in base all'esistenza di una chiave.

  • Supporta le espressioni nidificate collegate tramite parentesi e operatori logici. Gli operatori logici predefiniti sono AND se non sono presenti operatori tra le espressioni.

La query può essere utilizzata con altri filtri, ad esempio time_filters e folder_name_filter. Sono collegati all'operatore AND.

Le query di ricerca possono essere filtrate in base a parametri aggiuntivi, ad esempio property, time, schema, folder e creator.

Chiamata a una richiesta di ricerca

Per chiamare il servizio di ricerca, devi utilizzare una richiesta di ricerca, definita come segue:

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

Il campo parent deve essere compilato nel formato:

/projects/PROJECT_ID/locations/LOCATION

Risposta a una richiesta di ricerca

La risposta di ricerca è definita come segue:

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

Query sui documenti

Il campo document_query è definito come segue:

{
  "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)
  }
}

Il campo query contiene le parole della query di ricerca dell'utente richiedente. In genere, provengono dal campo di ricerca nell'interfaccia utente.

Filtri

Document AI Warehouse offre una serie di filtri.

Filtro temporale per i documenti

Il filtro per l'ora di creazione e aggiornamento funziona esattamente come ti aspetteresti: trova i documenti che corrispondono alle parole chiave entro un periodo di tempo specificato.

Un oggetto TimeFilter viene utilizzato per specificare l'intervallo di tempo ed è definito come segue:

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

Il campo time_field consente di specificare se l'intervallo di tempo specificato in time_range si riferisce all'ora di creazione del documento o all'ora dell'ultimo aggiornamento.

Il campo time_range specifica l'intervallo di tempo come Interval. Un Interval è definito come:

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

Filtro per creator

Per cercare documenti creati da uno o più utenti specifici, utilizza il filtro Autore. Ad esempio:

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

Filtro proprietà

Il filtro delle proprietà ti consente di specificare i filtri per qualsiasi proprietà specificata in uno schema, a condizione che sia stata configurata in modo da essere filtrabile.

Ad esempio, l'utilizzo di filtri delle proprietà nel settore legale potrebbe filtrare una proprietà denominata COURT per cercare solo i documenti di un determinato tribunale.

I filtri delle proprietà utilizzano un oggetto PropertyFilter. Puoi avere più di un filtro proprietà. Quando utilizzi più filtri delle proprietà, questi vengono combinati utilizzando l'operatore OR. Un filtro delle proprietà è definito come segue:

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

Le proprietà sono definite negli schemi. Pertanto, il campo documentSchemaName è quello in cui specifichi lo schema della proprietà che utilizzi per il filtro. Nel campo condition, specifica la logica che preferisci. Per esempi di utilizzo dei campi documentSchemaName e condition, consulta gli esempi precedenti in questa pagina.

Documento corrispondente

Un documento corrispondente contiene un elemento Document e uno snippet (di cui parleremo più avanti). Il documento restituito in MatchingDocument non è compilato completamente. Contiene i dati minimi per visualizzare un elenco di risultati di ricerca per l'utente richiedente. Se è necessario il documento completo (ad esempio, se l'utente ha fatto clic su un risultato di ricerca), il documento completo deve essere recuperato tramite l'API GetDocument.

I seguenti campi Document sono compilati: Project number, Document id, Document schema id, Create time, Update time, Display name, Raw document file type, Reference id e Filterable properties.

Un documento corrispondente sarà simile a questo:

{
  "document": {
    object (Document)
  },
  "searchTextSnippet": string,
  "qaResult": {
    object (QAResult)
  }
}

Ranking/ordinamento

La richiesta di ricerca ti consente di specificare come vuoi che vengano ordinati i risultati. Per ordinare, utilizza il campo order_by nella richiesta di ricerca. I valori possibili per questo campo includono:

  • relevance desc: pertinenza decrescente, ovvero le corrispondenze migliori sono in alto.
  • upload_date desc: la data di creazione del documento in ordine decrescente (il più recente in alto).
  • upload_date: la data di creazione del documento in ordine crescente (il più vecchio in alto).
  • update_date desc: la data dell'ultimo aggiornamento del documento in ordine decrescente (il più recente in alto).
  • Update_date: la data dell'ultimo aggiornamento del documento in ordine crescente (il più vecchio in alto).

Se non specifichi un ordinamento, ma fornisci parole chiave di ricerca, l'ordinamento viene eseguito in base alla pertinenza in ordine decrescente (le corrispondenze migliori in alto). Se non vengono forniti né l'ordinamento né le parole chiave, l'ordinamento predefinito è in base all'ora di aggiornamento in ordine decrescente (i documenti più recenti in alto).

Impaginazione

La paginazione è utile per mostrare all'utente finale una pagina di dati. Qui puoi specificare le dimensioni della pagina e ottenere un conteggio totale delle dimensioni dei risultati da mostrare all'utente (ad esempio "Visualizzazione di 50 documenti su 300").

Imposta il campo page_size sul numero di risultati che vuoi ricevere con la richiesta di ricerca. Ciò potrebbe corrispondere ai requisiti delle dimensioni di visualizzazione dei risultati di ricerca della UI.

Esistono due meccanismi: offset e token di pagina.

Un offset è l'indice nell'elenco dei documenti restituibili che vuoi restituire. Ad esempio, un offset di 5 significa che vuoi il sesto documento in poi. Presumibilmente, incrementeresti l'offset in base alla dimensione della pagina per la pagina successiva dei risultati.

In alternativa, puoi utilizzare un token di pagina e non preoccuparti di calcolare l'offset successivo. Dopo aver effettuato la prima richiesta di ricerca, ricevi una risposta di ricerca che contiene il campo next_page_token. Se questo campo è vuoto, non ci sono altri risultati. Se il campo non è vuoto, utilizza questo token nella richiesta di ricerca successiva impostando il campo page_token.

Alcune UI mostrano il conteggio dei documenti trovati dalla ricerca. Ad esempio, you are viewing 10 documents of 120. Per ottenere un conteggio dei documenti restituiti, imposta il campo require_total_size boolean della richiesta su True. Suggerimento: require_total_size=True comporta una penalità di rendimento. Imposta questo valore nella query della prima pagina, quindi impostalo su false in tutte le richieste successive, mantenendo il conteggio totale in una variabile locale.

Esempi di codice

Python

Per saperne di più, consulta la documentazione di riferimento dell'API Document AI Warehouse Python.

Per eseguire l'autenticazione in Document AI Warehouse, configura le Credenziali predefinite dell'applicazione. Per saperne di più, consulta Configura l'autenticazione per un ambiente di sviluppo locale.


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

Per saperne di più, consulta la documentazione di riferimento dell'API Document AI Warehouse Java.

Per eseguire l'autenticazione in Document AI Warehouse, configura le Credenziali predefinite dell'applicazione. Per saperne di più, consulta Configura l'autenticazione per un ambiente di sviluppo locale.

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);
    } 
  }
}

Passaggi successivi