Cómo buscar documentos

Antes de comenzar

Para transferir documentos de muestra a Document AI Warehouse, consulta la Guía de inicio rápido.

Cuando definas los esquemas de tus documentos y crees tus documentos, es importante que tengas en cuenta qué propiedades deseas definir y cómo se usarán con la búsqueda, si es que se usarán.

Marca una propiedad como filtrable si deseas usarla para incluir o excluir una parte de los documentos de una búsqueda. Por ejemplo, puedes hacer que una propiedad que representa un "proveedor" se pueda filtrar porque tus usuarios quieren buscar facturas de un proveedor específico.

Si deseas crear un histograma (consulta el ejemplo más adelante en este tema) en una propiedad, esta debe ser filtrable.

Marca una propiedad como apta para la búsqueda si tiene datos que tus usuarios querrán consultar durante una búsqueda por palabras clave.

La búsqueda de texto completo es el proceso de recuperar todos los documentos que coinciden con las palabras clave de búsqueda en su texto apto para búsquedas. El usuario proporciona una lista de palabras clave (palabras separadas por un espacio en blanco), presumiblemente escritas en un campo de búsqueda de la IU. En Document AI Warehouse, las palabras clave se procesan y se convierten en una consulta adecuada. Este procesamiento quita las palabras irrelevantes (“el”, “en” y “un”) y reduce las palabras restantes a su raíz. El stemming reduce la palabra a una versión común de la redacción, de modo que coincidan las variaciones de la palabra. Por ejemplo, "trabajo", "trabajando", "trabajé".

¿Qué datos se buscan?

  • Es el plain_text del documento.
  • Si importas un objeto de Document AI, usa el cloud_ai_document.text integrado.
  • Es el valor de display_name del documento.
  • Son todas las propiedades en las que se puede realizar una búsqueda.

La búsqueda admite parcialmente la sintaxis de estilo de Google AIP. Específicamente, la consulta admite literales, operadores lógicos, operadores de negación, operadores de comparación y funciones.

  • Literales: Un valor literal simple (por ejemplo, "42", "Hugo") es un valor con el que se debe hacer coincidir. Busca en el texto completo del documento y en las propiedades en las que se puede realizar búsquedas.
  • Operadores lógicos: "AND", "and", "OR" y "or" son operadores lógicos binarios (por ejemplo, "ingeniero OR desarrollador").
  • Operadores de negación: "NOT" y "!" son operadores de negación (por ejemplo, "NOT software").
  • Operadores de comparación: Se admiten los operadores de comparación binarios =, !=, <, >, <= y >= para cadenas, números, enumeraciones y valores booleanos. También se admite el operador like ~~ para cadenas. Proporciona funcionalidad de búsqueda semántica analizando, derivando y expandiendo sinónimos en la consulta de entrada.

    Para especificar una propiedad en la consulta, la expresión del lado izquierdo en la comparación debe ser el ID de la propiedad, incluido el elemento superior. El lado derecho debe contener literales. Por ejemplo, \"projects/123/locations/us\".property_a < 1 coincide con los resultados cuyo property_a es inferior a 1 en el proyecto 123 y la ubicación us. Los literales y la expresión de comparación se pueden conectar en una sola consulta (por ejemplo, software engineer \"projects/123/locations/us\".salary > 100).

  • Funciones: Las funciones admitidas son LOWER([property_name]) para realizar una coincidencia que no distingue mayúsculas de minúsculas y EMPTY([property_name]) para filtrar según la existencia de una clave.

  • Admite expresiones anidadas conectadas con paréntesis y operadores lógicos. El operador lógico predeterminado es AND si no hay operadores entre las expresiones.

La consulta se puede usar con otros filtros, p.ej., time_filters y folder_name_filter. Se conectan con el operador AND en segundo plano.

Las búsquedas se pueden filtrar con parámetros adicionales, como property, time, schema, folder y creator.

Llamada a una solicitud de búsqueda

Para llamar al servicio de búsqueda, debes usar una solicitud de búsqueda, que se define de la siguiente manera:

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

El campo parent debe completarse con el siguiente formato:

/projects/PROJECT_ID/locations/LOCATION

Respuesta a una solicitud de búsqueda

La respuesta de búsqueda se define de la siguiente manera:

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

Consulta de documentos

El campo document_query se define de la siguiente manera:

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

El campo query es para las palabras de la búsqueda del usuario solicitante. Por lo general, provienen del campo de búsqueda de la IU.

Filtros

Document AI Warehouse ofrece una variedad de filtros.

Filtro de tiempo del documento

El filtro de hora de creación y actualización es exactamente lo que esperas: encuentra documentos que coinciden con las palabras clave dentro de un período especificado.

Un objeto TimeFilter se usa para especificar el intervalo y se define de la siguiente manera:

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

En el campo time_field, se especifica si el período indicado en time_range corresponde a la hora de creación o a la hora de la última actualización del documento.

El campo time_range especifica el intervalo de tiempo como un Interval. Un Interval se define de la siguiente manera:

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

Filtro de creador

Para buscar documentos creados por un usuario o usuarios específicos, usa el filtro de creador. Por ejemplo:

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

Filtro de propiedad

El filtro de propiedad te permite especificar filtros en cualquiera de las propiedades que hayas especificado en un esquema, siempre y cuando esa propiedad se haya configurado para que se pueda filtrar.

Por ejemplo, usar filtros de propiedad en la industria legal podría filtrar una propiedad llamada COURT para buscar solo documentos de un tribunal en particular.

Los filtros de propiedades usan un objeto PropertyFilter. Puedes tener más de un filtro de propiedad. Cuando usas varios filtros de propiedad, se combinan con el operador OR. Un filtro de propiedad se define de la siguiente manera:

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

Las propiedades se definen en esquemas. Por lo tanto, el campo documentSchemaName es donde especificas el esquema de la propiedad que usas para filtrar. En el campo condition, especifica la lógica deseada. Para ver ejemplos del uso de los campos documentSchemaName y condition, consulta los ejemplos anteriores en esta página.

Documento coincidente

Un documento coincidente contiene un Document y un fragmento (que se analizarán más adelante). El documento que se devolvió en MatchingDocument no está completo. Contiene la cantidad mínima de datos para mostrar una lista de resultados de la búsqueda al usuario solicitante. Si se desea el documento completo (por ejemplo, si el usuario hizo clic en un resultado de la búsqueda), se debe recuperar a través de la API de GetDocument.

Se completan los siguientes campos de Document: Project number, Document id, Document schema id, Create time, Update time, Display name, Raw document file type, Reference id y Filterable properties.

Un documento coincidente se vería de la siguiente manera:

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

Clasificación o orden

La solicitud de búsqueda te permite especificar cómo quieres que se ordenen los resultados. Para ordenar, usa el campo order_by en la solicitud de búsqueda. Los valores posibles para este campo incluyen los siguientes:

  • relevance desc: Relevancia descendente, es decir, las mejores coincidencias se encuentran en la parte superior.
  • upload_date desc: Es la fecha en la que se creó el documento en orden descendente (el más reciente en la parte superior).
  • upload_date: La fecha en que se creó el documento en orden ascendente (el más antiguo en la parte superior).
  • update_date desc: La fecha en que se actualizó el documento por última vez en orden descendente (el más reciente en la parte superior).
  • Update_date: La fecha en que se actualizó el documento por última vez en orden ascendente (el más antiguo en la parte superior).

Si no especificas una clasificación, pero proporcionas palabras clave de búsqueda, la clasificación se realizará por relevancia descendente (las mejores coincidencias en la parte superior). Si no se proporcionan la ordenación ni las palabras clave, la ordenación predeterminada es por hora de actualización descendente (los documentos más recientes en la parte superior).

Paginación

La paginación es útil para mostrar una página de datos al usuario final. Aquí puedes especificar el tamaño de la página y obtener un recuento total del tamaño del resultado para mostrarlo al usuario (por ejemplo, "Se muestran 50 documentos de 300").

Establece el campo page_size en la cantidad deseada de resultados que deseas recibir con la solicitud de búsqueda. Esto podría corresponder a los requisitos del tamaño de visualización del resultado de la búsqueda de la IU.

Existen dos mecanismos: el desplazamiento y el token de página.

Un desplazamiento es el índice en la lista de documentos que se pueden devolver que deseas que se devuelvan. Por ejemplo, un desplazamiento de 5 significa que quieres el sexto documento en adelante. Es probable que aumentes el desplazamiento según el tamaño de la página para la siguiente página de resultados.

Como alternativa, puedes usar un token de página y no tener que preocuparte por calcular la próxima compensación. Después de realizar tu primera solicitud de búsqueda, obtendrás una respuesta de búsqueda que contiene el campo next_page_token. Si este campo está vacío, significa que no hay más resultados. Si el campo no está vacío, usa este token en tu próxima solicitud de búsqueda configurando el campo page_token.

Algunas IU muestran el recuento de documentos que encontró la búsqueda. Por ejemplo, you are viewing 10 documents of 120. Para obtener un recuento de documentos, configura el campo require_total_size boolean de la solicitud en True. Nota: require_total_size=True conlleva una penalización de rendimiento. Establece este parámetro en la consulta de la primera página y, luego, establécelo en false en todas las solicitudes posteriores, manteniendo el recuento total en una variable local.

Muestras de código

Python

Para obtener más información, consulta la documentación de referencia de la API de Document AI Warehouse Python.

Para autenticarte en Document AI Warehouse, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.


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

Para obtener más información, consulta la documentación de referencia de la API de Document AI Warehouse Java.

Para autenticarte en Document AI Warehouse, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

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

Próximos pasos