Estrutura e formato dos dados de entrada

Para criar um novo índice ou atualizar um existente, forneça vetores ao Vector Search no formato e na estrutura descritos nas seções a seguir.

Armazenamento de dados de entrada e organização de arquivos

Pré-requisito

Armazene os dados de entrada em um bucket do Cloud Storage no projeto do Google Cloud.

Os arquivos de dados de entrada precisam ser organizados da seguinte maneira:

  • Cada lote de arquivos de dados de entrada precisa estar em um único diretório do Cloud Storage.
  • Os arquivos de dados precisam ser colocados diretamente em batch_root e nomeados com os seguintes sufixos: .csv, .json e .avro.
  • Há um limite de 5.000 objetos no diretório raiz do lote.
  • Cada arquivo de dados é interpretado como um conjunto de registros. O formato do registro é determinado pelo sufixo do nome do arquivo, e esses requisitos de formato são descritos. Consulte Formatos de arquivo de dados.
  • Cada registro precisa ter um id, um vetor de recurso e campos opcionais compatíveis com o Feature Store da Vertex AI, como restrições e distanciamento.
  • Um subdiretório chamado delete pode estar presente. Cada arquivo diretamente colocado em batch_root/delete é processado como um arquivo de texto de registros id com um id em cada linha.
  • Todos os outros subdiretórios não são permitidos.

Processamento de dados de entrada

  • Todos os registros de todos os arquivos de dados, incluindo aqueles em delete, consistem em um único lote de entrada.
  • A ordem relativa dos registros em um arquivo de dados não é importante.
  • Um único ID só deve aparecer uma vez em um lote. Se houver uma cópia com o mesmo ID, ela será mostrada como uma contagem de vetores.
  • Um ID não pode aparecer em um arquivo de dados normal e em um arquivo de dados de exclusão.
  • Todos os IDs de um arquivo de dados em exclusão fazem com que ele seja removido da próxima versão do índice.
  • Os registros de arquivos de dados regulares serão incluídos na próxima versão, possivelmente substituindo um valor em uma versão de índice mais antiga.

Confira a seguir exemplos de embeddings densos, esparsos e híbridos:

  • Embeddings densos

    {"id": "1", "embedding": [1,1,1]}
    {"id": "2", "embedding": [2,2,2]}
    
  • Embeddings esparsos (pré-lançamento público):

    {"id": "3", "sparse_embedding": {"values": [0.1, 0.2], "dimensions": [1, 4]}}
    {"id": "4", "sparse_embedding": {"values": [-0.4, 0.2, -1.3], "dimensions": [10, 20, 20]}}
    
  • Embeddings híbridos (pré-lançamento público):

    {"id": "5", "embedding": [5, 5, -5], "sparse_embedding": {"values": [0.1], "dimensions": [500]}}
    {"id": "6", "embedding": [6, 7, -8.1], "sparse_embedding": {"values": [0.1, -0.2], "dimensions": [40, 901]}}
    

Veja a seguir um exemplo de organização válida de arquivos de dados de entrada:

batch_root/
  feature_file_1.csv
  feature_file_2.csv
  delete/
    delete_file.txt

Os arquivos feature_file_1.csv e feature_file_2.csv contêm registros no formato CSV. O arquivo delete_file.txt contém uma lista de IDs de registro a serem excluídos da próxima versão do índice.

Formatos de arquivo de dados

JSON

  • Codifique o arquivo JSON usando UTF-8.
  • Cada linha do arquivo JSON será interpretada como um objeto JSON separado.
  • Cada registro precisa conter um campo id para especificar o ID do vetor.
  • Cada registro precisa conter pelo menos embedding ou sparse_embedding.
  • O campo embedding é uma matriz de números de ponto flutuante N que representa o vetor de atributos, em que N é a dimensão do vetor de atributos que foi configurado quando o índice foi criado. Esse campo só pode ser usado para embeddings densos.
    • O configs.dimensions, especificado no momento da criação do índice, precisa ter o mesmo comprimento que embeddings. configs.dimensions se aplica apenas a embedding, não a sparse_embedding.
  • O campo sparse_embedding é um objeto com campos values e dimensions. O campo values é uma lista de números de pontos flutuantes que representam o vetor do atributo e o campo dimensions é uma lista de números inteiros que representa a dimensão na qual o valor correspondente está localizado. Por exemplo, um embedding esparso que se parece com [0,0.1,0,0,0.2] pode ser representado como "sparse_embedding": {"values": [0.1, 0.2], "dimensions": [1,4]}. Isso pode ser usado apenas para embeddings esparsos.
    • O comprimento de sparse_embedding.values precisa ser igual ao de sparse_embedding.dimensions. Elas não precisam ter o mesmo tamanho que configs.dimensions, que é especificado no momento da criação do índice e não se aplica a sparse_embedding.
  • É possível incluir um campo restricts opcional para especificar uma matriz de objetos TokenNamespace em restrições. Para cada objeto:
    • Especifique um campo namespace que seja o TokenNamespace.namespace.
    • Um campo allow opcional pode ser definido como uma matriz de strings, que são a lista de TokenNamespace.string_tokens.
    • Um campo deny opcional pode ser definido como uma matriz de strings, que são a lista de TokenNamespace.string_blacklist_tokens.
    • O valor do campo crowding_tag, se presente, precisa ser uma string.
  • É possível incluir um campo numeric_restricts opcional que especifica uma matriz de NumericRestrictNamespace. Para cada objeto:
    • Especifique um campo namespace que seja o NumericRestrictNamespace.namespace.
    • Um dos campos de valor value_int, value_float e value_double.
    • Ele não pode ter um campo chamado op. Esse campo é apenas para consultas.

Avro

  • Use um arquivo Avro válido.
  • Para representar um ponto de dados apenas com valores esparsos, forneça uma embedding esparso no campo sparse_embedding e insira uma lista vazia no campo embedding.
  • Faça registros que estejam em conformidade com o seguinte esquema:

    {
      "type": "record",
      "name": "FeatureVector",
      "fields": [
        {
          "name": "id",
          "type": "string"
        },
        {
          "name": "embedding",
          "type": {
            "type": "array",
            "items": "float"
          }
        },
        {
          "name": "sparse_embedding",
          "type": [
            "null",
            {
              "type": "record",
              "name": "sparse_embedding",
              "fields": [
                {
                  "name": "values",
                  "type": {
                    "type": "array",
                    "items": "float"
                  }
                },
                {
                  "name": "dimensions",
                  "type": {
                    "type": "array",
                    "items": "long"
                  }
                }
              ]
            }
          ]
        },
        {
          "name": "restricts",
          "type": [
            "null",
            {
              "type": "array",
              "items": {
                "type": "record",
                "name": "Restrict",
                "fields": [
                  {
                    "name": "namespace",
                    "type": "string"
                  },
                  {
                    "name": "allow",
                    "type": [
                      "null",
                      {
                        "type": "array",
                        "items": "string"
                      }
                    ]
                  },
                  {
                    "name": "deny",
                    "type": [
                      "null",
                      {
                        "type": "array",
                        "items": "string"
                      }
                    ]
                  }
                ]
              }
            }
          ]
        },
        {
          "name": "numeric_restricts",
          "type": [
            "null",
            {
              "type": "array",
              "items": {
                "name": "NumericRestrict",
                "type": "record",
                "fields": [
                  {
                    "name": "namespace",
                    "type": "string"
                  },
                  {
                    "name": "value_int",
                    "type": [ "null", "int" ],
                    "default": null
                  },
                  {
                    "name": "value_float",
                    "type": [ "null", "float" ],
                    "default": null
                  },
                  {
                    "name": "value_double",
                    "type": [ "null", "double" ],
                    "default": null
                  }
                ]
              }
            }
          ],
          "default": null
        },
        {
          "name": "crowding_tag",
          "type": [
            "null",
            "string"
          ]
        }
      ]
    }
    

CSV

  • Formato: ID,N feature vector values,Any number of dimension:value sparse values,name=value lists
  • Codifique o arquivo CSV usando UTF-8.
  • Cada linha do CSV precisa conter exatamente um registro.
  • O primeiro valor em cada linha precisa ser o ID do vetor, que precisa ser uma string UTF-8 válida.
  • Após o ID, pelo menos um dos embeddings densos ou esparsos precisa ser especificado.
  • Para um embedding denso, os próximos valores de N representam o vetor de atributo, em que N é a dimensão do vetor de atributo que foi configurada quando o índice foi criado.
  • Em um embedding esparso, qualquer número de dimension:value pode ser especificado, em que value é analisado como um ponto flutuante e dimension é analisado como um long.
  • Para um embedding híbrido com embeddings densos e esparsos, os densos precisam ser especificados antes dos esparsos.
  • Os valores de vetor de recurso precisam ser literais de ponto flutuante, conforme definido na especificação da linguagem Java.
  • Os valores adicionais podem estar no formato name=value.
  • O nome crowding_tag é interpretado como a tag de distanciamento e só pode aparecer uma vez no registro.
  • Todos os outros pares name=value são interpretados como restrições de namespace. O mesmo nome pode ser repetido se houver vários valores em um namespace.

    Por exemplo, color=red,color=blue representa este TokenNamespace:

    {
      "namespace": "color"
      "string_tokens": ["red", "blue"]
    }
    
  • Se o valor começar com !, o restante da string será interpretado como um valor excluído.

    Por exemplo, color=!red representa este TokenNamespace:

    {
      "namespace": "color"
      "string_blacklist_tokens": ["red"]
    }
    
  • Pares #name=numericValue com sufixo de tipo numérico são interpretados como restrições numéricas de namespace. O sufixo do tipo de número é i para int, f para flutuante e d para duplo. O mesmo nome não pode ser repetido, porque precisa haver um único valor associado por namespace.

    Por exemplo, #size=3i representa este NumericRestrictNamespace:

    {
      "namespace": "size"
      "value_int": 3
    }
    

    #ratio=0.1f representa este NumericRestrictNamespace:

    {
      "namespace": "ratio"
      "value_float": 0.1
    }
    

    #weight=0.3d representa este NumericRestriction:

    {
      "namespace": "weight"
      "value_double": 0.3
    }
    
  • O exemplo a seguir é um ponto de dados com id: "6", embedding: [7, -8.1], sparse_embedding: {values: [0.1, -0.2, 0.5], dimensions: [40, 901, 1111]}}, tag de distanciamento test, lista de permissões de token do color: red, blue, lista de bloqueio de token do color: purple e restrição numérica do ratio com 0.1 flutuante:

    6,7,-8.1,40:0.1,901:-0.2,1111:0.5,crowding_tag=test,color=red,color=blue,color=!purple,ratio=0.1f
    

A seguir