Modificar el esquema de una colección

A medida que una colección pasa de la fase de desarrollo a la de producción, su esquema suele cambiar. Es posible que añadas campos escalares, como « source_uri » o « review_status », para el filtrado y la lógica de la aplicación; que añadas un nuevo campo vectorial para las incrustaciones generadas por tu aplicación; que añadas una función BM25 y su campo vectorial disperso generado para la búsqueda léxica en el texto existente; o que elimines campos y funciones que ya no se utilicen. La opción «Modificar el esquema de la colección» le permite realizar cambios compatibles en los campos y las funciones sin necesidad de volver a crear la colección.

Esta guía aborda los cambios en el esquema de los campos definidos por el usuario y de las funciones con sus campos vectoriales generados en colecciones gestionadas. Para añadir un campo a una colección externa, consulta «Modificar el esquema de una colección externa». Para cambios en las propiedades de los campos, como modificar « max_length » en un campo de « VARCHAR » o « max_capacity » en un campo de « ARRAY », consulta «Modificar un campo de la colección». Para el comportamiento dinámico de los campos, consulte «Campo dinámico » y «Modificar colección».

Límites

Añadir campos definidos por el usuario

  • Los campos definidos por el usuario que se añadan deben ser nulos. Establezca nullable=True al llamar a add_collection_field(). Para las entidades existentes, el campo añadido es de tipo NULL, a menos que añada un campo escalar con default_value.

  • La adición de campos escalares definidos por el usuario es compatible con Milvus 2.6.x y versiones posteriores. La adición de campos vectoriales definidos por el usuario es compatible con Milvus 2.6.18 y versiones posteriores.

  • La adición de campos StructArray es compatible con Milvus 3.0.0 y versiones posteriores. Los campos StructArray añadidos deben ser nulos.

  • Los nombres de los campos deben ser únicos entre los campos de la colección.

Añadir una función y su campo vectorial generado

  • Cada actualización del esquema solo puede añadir una función y un campo vectorial generado.

  • La función admitida determina el tipo de campo vectorial generado: « BM25 » genera un campo « SPARSE_FLOAT_VECTOR », y « MINHASH » genera un campo « BINARY_VECTOR ».

  • El campo vectorial generado debe ser un campo nuevo. No puede hacer referencia a un campo que ya exista en el esquema de la colección.

  • El campo vectorial generado no puede ser nulo.

  • Los campos de entrada utilizados por la función deben existir ya en la colección.

  • Al añadir una función BM25 o MinHash a una colección existente, la entrada de la función debe ser un campo de tipo « VARCHAR ». No se admite una entrada de tipo « TEXT » en este flujo de trabajo, ya que Milvus no puede rellenar retrospectivamente la salida generada para las entidades existentes a partir de ese tipo de entrada.

Eliminar campos definidos por el usuario

  • No se puede eliminar el campo de clave primaria, el campo de clave de partición, el campo de clave de agrupamiento ni el último campo vectorial de una colección.

  • Se puede eliminar un campo « ARRAY<STRUCT> » completo, pero no se puede eliminar un subcampo individual dentro de un campo « ARRAY<STRUCT> ».

  • No se puede eliminar directamente un campo que se utilice como campo de entrada de una función o que se haya generado como campo de salida de una función. Para eliminar un campo de salida de una función, elimine la función que lo genera.

Eliminar una función y su campo vectorial generado

  • En este flujo de trabajo de cambio de esquema, al eliminar una función se eliminan la función, su campo vectorial generado y el índice asociado. Los campos de entrada de la función permanecen en el esquema de la colección.

  • La eliminación de una función se rechaza si, al eliminar su campo vectorial generado, la colección quedara sin ningún campo vectorial.

Para cambios de esquema que no se incluyan en las operaciones de adición y eliminación admitidas, vuelve a crear o migra la colección.

Añadir campos y funciones a una colección existente

Elige el flujo de trabajo en función de si vas a añadir un campo definido por el usuario o una función que genere un campo vectorial:

En todos los casos, el nombre del nuevo campo no debe existir ya en la colección, y el número total de campos no puede superar el límite de Milvus para el número de campos. Para más detalles, consulta Límites de Milvus.

Añadir campos escalares definidos por el usuarioCompatible with Milvus 2.6.x

Utilice « add_collection_field() » para añadir un campo escalar definido por el usuario a una colección existente.

Esto difiere del almacenamiento de claves arbitrarias en el campo dinámico: una vez que la actualización del esquema está disponible, el nuevo campo escalar pasa a formar parte del esquema de la colección. Puede insertar o actualizar valores en él, crear índices sobre él cuando sea compatible, utilizarlo en consultas y filtros de búsqueda, y devolverlo en el resultado de una consulta o búsqueda.

Dado que las entidades existentes se insertaron antes de que existiera el nuevo campo, todo campo escalar definido por el usuario que se añada debe ser nulo:

  • Si se añade un campo escalar con ` nullable=True ` y sin ` default_value`, las entidades existentes devuelven ` NULL ` para el nuevo campo.

  • Si se añade un campo escalar con ` nullable=True ` y ` default_value`, las entidades existentes devolverán el valor por defecto en lugar de ` NULL`.

Las expresiones de filtro escalares no coinciden con los valores escalares de tipo « NULL ». Para obtener más información, consulta «Campos nulos».

Ejemplo: Añadir un campo escalar nulo

En el siguiente ejemplo se añade un campo escalar nulo source a una colección existente denominada product_catalog.

from pymilvus import DataType, MilvusClient

client = MilvusClient(uri="http://localhost:19530")

client.add_collection_field(
    collection_name="product_catalog",
    field_name="source",
    data_type=DataType.VARCHAR,
    max_length=128,
    nullable=True,
)

Una vez añadido el campo, las entidades que ya existían en la colección devuelven « NULL » para « source ». Las nuevas entidades pueden establecer « source » durante la inserción o la actualización.

Ejemplo: Añadir un campo escalar con un valor por defecto

Si se desea que las entidades existentes devuelvan un valor concreto en lugar de « NULL », especifique « default_value » al añadir un campo escalar. El siguiente ejemplo añade un campo « review_status » y utiliza « "unreviewed" » como valor por defecto.

from pymilvus import DataType, MilvusClient

client = MilvusClient(uri="http://localhost:19530")

client.add_collection_field(
    collection_name="product_catalog",
    field_name="review_status",
    data_type=DataType.VARCHAR,
    max_length=32,
    nullable=True,
    default_value="unreviewed",
)

Una vez añadido el campo, las entidades que ya existían en la colección devuelven "unreviewed" para review_status. Las nuevas entidades pueden establecer un valor diferente o utilizar el valor por defecto cuando no se proporcione ningún valor.

Añadir campos StructArrayCompatible with Milvus 3.0.0

Utilice add_collection_struct_field() para añadir un campo StructArray que acepte matrices de elementos Struct. Para añadir un campo StructArray, proceda de la siguiente manera:

  1. Crea un esquema Struct que contenga los subcampos necesarios de los tipos de datos admitidos. Para conocer los tipos de datos aplicables, consulta Límites de StructArray.

  2. Haga referencia al esquema Struct creado anteriormente y establezca la capacidad máxima del campo en « add_collection_struct_field() ».

  3. Establece nullable=True en la solicitud.

Ejemplo: Añadir un campo StructArray nulo

from pymilvus import DataType, MilvusClient

client = MilvusClient(uri="http://localhost:19530")

# Create a Struct schema.
struct_schema = client.create_struct_field_schema()

# Add scalar fields to the Struct.
struct_schema.add_field("text", DataType.VARCHAR, max_length=65535)
struct_schema.add_field("chapter", DataType.VARCHAR, max_length=512)

# Add vector fields to the Struct with mmap enabled.
struct_schema.add_field("text_vector", DataType.FLOAT_VECTOR, mmap_enabled=True, dim=5)
struct_schema.add_field("chapter_vector", DataType.FLOAT_VECTOR, mmap_enabled=True, dim=5)

client.add_collection_struct_field(
    collection_name="books",
    field_name="chunks",
    struct_schema=struct_schema,
    max_capacity=1024,
    nullable=True,
)

Una vez añadido el campo StructArray, las entidades que ya existen en la colección devuelven « NULL » para « chunks » en todos sus subcampos. Al insertar una nueva entidad, asegúrate de que todos los subcampos sean « NULL » o tengan valores válidos. Insertar una entidad con algunos subcampos establecidos en « NULL » y otros con valores válidos da lugar a errores.

Añadir campos vectoriales definidos por el usuarioCompatible with Milvus 2.6.18+

Utiliza add_collection_field() para añadir un campo vectorial definido por el usuario cuando tu aplicación genere representaciones y escriba valores vectoriales en Milvus.

Todos los campos vectoriales definidos por el usuario que se añadan deben ser nulos. Las entidades existentes tendrán el valor « NULL » para el nuevo campo vectorial hasta que se escriban valores vectoriales mediante un flujo de trabajo de «upsert» o de «backfill». Las nuevas entidades pueden incluir el campo vectorial durante la inserción. La búsqueda vectorial omite las entidades cuyo valor vectorial sea « NULL ». Para obtener más detalles, consulta «Campos nulos».

Ejemplo: Añadir un campo vectorial nulo

En el siguiente ejemplo se añade un campo vectorial denso nulo denominado « embedding_v2 » a una colección existente. Establezca « dim » en la dimensionalidad de las incrustaciones generadas por su aplicación.

from pymilvus import DataType, MilvusClient

client = MilvusClient(uri="http://localhost:19530")

client.add_collection_field(
    collection_name="product_catalog",
    field_name="embedding_v2",
    data_type=DataType.FLOAT_VECTOR,
    dim=768,
    nullable=True,
)

Una vez añadido el campo, cree un índice en el nuevo campo vectorial antes de realizar búsquedas en él:

index_params = client.prepare_index_params()

index_params.add_index(
    field_name="embedding_v2",
    index_type="AUTOINDEX",
    metric_type="COSINE",
)

client.create_index(
    collection_name="product_catalog",
    index_params=index_params,
)

Las entidades existentes tienen NULL para embedding_v2 y se omiten al realizar búsquedas en este campo. Para que las entidades existentes sean buscables mediante embedding_v2, escriba valores vectoriales distintos de NULL mediante un flujo de trabajo de «upsert» o de «backfill». Las nuevas entidades pueden incluir embedding_v2 durante la inserción.

Añadir una función y su campo vectorial generadoCompatible with Milvus 3.0.x

Utilice este flujo de trabajo cuando Milvus deba generar un nuevo campo vectorial a partir de datos ya almacenados en una colección existente. La operación añade tres elementos de esquema relacionados:

  • Una definición de función que lee a partir de uno o más campos de entrada existentes.

  • Un nuevo campo vectorial que almacena la salida de la función.

  • Una definición de índice vinculada al nuevo campo vectorial.

Por ejemplo, una función BM25 lee un campo « VARCHAR » ya existente y genera un campo « SPARSE_FLOAT_VECTOR » para la búsqueda léxica. Una función MinHash genera un campo « BINARY_VECTOR » para la detección de casi duplicados. Este flujo de trabajo no añade ni sustituye el campo de entrada de la función.

Esta función requiere Storage V3. Para obtener instrucciones de activación y consideraciones de compatibilidad, consulte Storage V3.

Añadir una función y su campo vectorial generado a una colección existente también requiere la compactación de la versión del esquema y la compactación de la versión de almacenamiento. Milvus rechaza la solicitud si alguno de estos ajustes está desactivado. Estos requisitos previos adicionales solo se aplican al modificar una colección existente; la definición de la función en el esquema inicial de la colección no utiliza este flujo de trabajo de rellenado de datos existentes.

La función compatible determina el tipo de campo vectorial generado:

FunciónTipo de campo vectorial generadoCampo de entrada típicoCaso de uso típico
BM25SPARSE_FLOAT_VECTORUn campo « VARCHAR » con el analizador activadoBúsqueda léxica y relevancia de palabras clave
MINHASHBINARY_VECTORUn campo « VARCHAR »Detección de casi duplicados

Para obtener más información sobre cómo funciona cada función, consulta «Función BM25 » y «Función MinHash».

El campo vectorial generado no debe existir ya en la colección y no puede ser nulo. El campo de entrada de la función debe existir ya.

Ejemplo: Añadir una función BM25 y su campo vectorial disperso generado

El siguiente ejemplo añade una función BM25 denominada « text_bm25 » y su campo vectorial disperso generado, denominado « text_sparse », a una colección existente. La colección debe contar ya con un campo « VARCHAR » denominado « text » con el analizador habilitado.

from pymilvus import DataType, Function, FunctionType, MilvusClient

client = MilvusClient(uri="http://localhost:19530")

sparse_field = client.create_field_schema(
    name="text_sparse",
    data_type=DataType.SPARSE_FLOAT_VECTOR,
    desc="BM25-generated sparse vector field",
)

bm25_function = Function(
    name="text_bm25",
    input_field_names=["text"],
    output_field_names=["text_sparse"],
    function_type=FunctionType.BM25,
)

index_params = client.prepare_index_params()

index_params.add_index(
    field_name="text_sparse",
    index_type="SPARSE_INVERTED_INDEX",
    metric_type="BM25",
    params={
        "inverted_index_algo": "DAAT_MAXSCORE",
        "bm25_k1": 1.2,
        "bm25_b": 0.75,
    },
)

client.add_function_field(
    collection_name="product_catalog",
    field_schema=sparse_field,
    func=bm25_function,
    index_params=index_params,
)

El objeto « index_params » debe contener exactamente una definición de índice para el nuevo campo de salida de la función. Milvus añade la función, su campo vectorial generado y la definición de índice vinculado en el mismo cambio de esquema. No llames a « create_index() » por separado después de « add_function_field() ».

Conceptualmente, esta operación añade las siguientes definiciones de «Function», campo de salida generado e índice vinculado:

New Function:
  name: "text_bm25"
  type: BM25
  input_field_names: ["text"]
  output_field_names: ["text_sparse"]

New generated output field:
  name: "text_sparse"
  data_type: SPARSE_FLOAT_VECTOR
  nullable: false

Bound index:
  field_name: "text_sparse"
  index_type: SPARSE_INVERTED_INDEX
  metric_type: BM25

Una vez que la solicitud se ha completado con éxito, describe_collection() devuelve tanto la nueva función text_bm25 como su campo vectorial generado text_sparse en el esquema de la colección. Milvus genera la salida de la función para las nuevas entidades a medida que se escriben. En el caso de las entidades existentes, Milvus rellena el campo vectorial generado de forma asíncrona mediante una compactación en segundo plano. La visibilidad del esquema confirma que la actualización del esquema se ha realizado correctamente, pero no indica que el rellenado se haya completado para todas las entidades existentes. Para conocer el flujo de trabajo completo de búsqueda BM25, consulta «Búsqueda de texto completo».

Milvus también admite funciones MinHash y sus campos vectoriales binarios generados para la detección de casi duplicados. Una función MinHash utiliza FunctionType.MINHASH y escribe en un nuevo campo de salida BINARY_VECTOR. Para obtener detalles sobre la configuración, consulte «Función MinHash».

Eliminar campos y funciones de una colección existente

Puede eliminar campos definidos por el usuario directamente cuando ya no formen parte de su modelo de colección. Para eliminar una función y su campo vectorial generado, elimine la función; Milvus eliminará el campo generado y su índice en el mismo cambio de esquema.

Eliminar campos definidos por el usuarioCompatible with Milvus 3.0.x

Utilice « drop_collection_field() » para eliminar un campo escalar, vectorial o StructArray definido por el usuario que ya no forme parte de su modelo de colección.

Al eliminar un campo, primero se modifican el esquema de la colección y la visibilidad del campo:

  • Una vez que se ha ejecutado correctamente « drop_collection_field() », se actualiza el esquema de la colección: « describe_collection() » ya no devuelve el campo eliminado, y las consultas o búsquedas ya no pueden devolver dicho campo en « output_fields » ni utilizarlo en expresiones.

  • Los índices creados sobre el campo eliminado se limpian como parte de la actualización del esquema.

La limpieza del almacenamiento se gestiona por separado de la limpieza del esquema. Para obtener más detalles, consulta «¿Cuándo se recupera el espacio de almacenamiento tras eliminar un campo?».

Ejemplo: Eliminar un campo escalar definido por el usuario

El siguiente ejemplo da por hecho que « experiment_tag » es un campo escalar definido por el usuario en « product_catalog » y lo elimina de la colección.

from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530")

client.drop_collection_field(
    collection_name="product_catalog",
    field_name="experiment_tag",
)

Tras eliminar un campo, puede llamar a ` describe_collection() ` para comprobar que el campo ya no forma parte del esquema.

Ejemplo: Eliminar un campo StructArray

El siguiente ejemplo parte de la base de que ` chunks ` es un campo `StructArray` en ` my_collection` y lo elimina de la colección.

from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530")

client.drop_collection_field(
    collection_name="my_collection",
    field_name="chunks",
)

Ejemplo: Eliminar un campo vectorial definido por el usuario

Se puede eliminar un campo vectorial con el mismo método ` drop_collection_field() `, pero la colección debe seguir conteniendo al menos un campo vectorial tras la eliminación. Esto resulta útil para colecciones que contienen temporalmente varias representaciones vectoriales y que posteriormente se estandarizan en una de ellas.

El siguiente ejemplo parte de la base de que « image_vector » es un campo vectorial definido por el usuario en « hybrid_catalog », y de que la colección sigue conservando otro campo vectorial, como « text_vector ».

from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530")

client.drop_collection_field(
    collection_name="hybrid_catalog",
    field_name="image_vector",
)

Si image_vector es el último campo vectorial de la colección, la operación de eliminación se rechaza.

Eliminar una función y su campo vectorial generadoCompatible with Milvus 3.0.x

Utilice esta operación cuando ya no necesite una función o su campo vectorial generado, como una función BM25 y su campo vectorial disperso generado.

Llame a drop_function_field() con el nombre de la función. Milvus elimina la función, su campo vectorial generado y el índice asociado, al tiempo que conserva los campos de entrada de la función.

Ejemplo: Eliminar una función BM25 y su campo vectorial disperso generado

En el siguiente ejemplo se supone que « text_bm25 » es una función BM25 en « product_catalog » y genera un campo de salida vectorial disperso denominado « text_sparse ».

from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530")

client.drop_function_field(
    collection_name="product_catalog",
    function_name="text_bm25",
)

Una vez que la operación se ha realizado con éxito, describe_collection() ya no devuelve la función eliminada ni su campo vectorial generado. Los campos de entrada de la función permanecen en el esquema.

Si al eliminar el campo de salida de la función la colección quedara sin ningún campo vectorial, la operación se rechaza.

Preguntas frecuentes

¿Qué método debo utilizar para añadir un campo o una función?

Utiliza add_collection_field() para añadir un campo escalar o vectorial definido por el usuario.

Utilice ` add_collection_struct_field() ` para añadir un campo `StructArray` cuando necesite un campo de matriz cuyos elementos compartan el mismo esquema `Struct`.

Utiliza « add_function_field() » para añadir una función, su campo vectorial generado y la definición del índice vinculado en el mismo cambio de esquema.

¿Por qué los campos definidos por el usuario que se añaden deben ser nulos?

Las entidades existentes se insertaron antes de que existiera el nuevo campo, por lo que no tienen valores para ese campo. Al establecer ` nullable=True `, Milvus representa el valor que falta como ` NULL ` hasta que su aplicación escriba un valor o, en el caso de los campos escalares, hasta que se aplique un valor por defecto.

Esta regla se aplica a los campos escalares definidos por el usuario y a los campos vectoriales definidos por el usuario añadidos con ` add_collection_field()`, así como a los campos `StructArray` añadidos con ` add_collection_struct_field()`. No se aplica al campo vectorial generado por una función, que no puede ser nulo.

¿Qué ocurre con las entidades existentes después de añadir un campo definido por el usuario?

En el caso de un campo escalar definido por el usuario, las entidades existentes devuelven NULL a menos que se establezca un default_value. Si se establece un default_value, las entidades existentes devuelven ese valor por defecto.

En el caso de un campo vectorial definido por el usuario, las entidades existentes tienen el valor « NULL » para el nuevo campo vectorial. La búsqueda vectorial en el campo añadido omite las entidades cuyo valor vectorial sea « NULL ». Para que las entidades existentes sean buscables a través del nuevo campo vectorial, escribe valores vectoriales distintos de NULL mediante «upsert» o un flujo de trabajo de rellenado. Las nuevas entidades pueden incluir el nuevo campo vectorial durante la inserción.

En el caso de un campo StructArray, las entidades existentes devuelven « NULL » para el nuevo campo StructArray en todos sus subcampos. Las nuevas entidades deben proporcionar « NULL » para todos los subcampos o valores válidos para todos los subcampos.

¿Puedo añadir la búsqueda léxica BM25 a una colección existente?

Sí. Si la colección ya cuenta con un campo « VARCHAR » con el analizador habilitado, puedes añadir una función BM25 y su campo vectorial disperso generado para la búsqueda léxica. En este flujo de trabajo, Milvus añade la función, el nuevo campo de salida « SPARSE_FLOAT_VECTOR » y la definición del índice vinculado en el mismo cambio de esquema. No se puede utilizar un campo « TEXT » ya existente como entrada de BM25 en este flujo de trabajo de cambio de esquema. Para utilizar una entrada de « TEXT », defina el campo y la función BM25 al crear la colección.

Al llamar a ` add_function_field()`, proporcione un objeto ` index_params ` que contenga un índice ` SPARSE_INVERTED_INDEX ` con ` metric_type="BM25" ` para el nuevo campo de salida. Milvus vincula la definición del índice al campo generado como parte del mismo cambio de esquema.

¿Cómo elimino una función y su campo vectorial generado?

Llama a drop_function_field() con el nombre de la función. En este flujo de trabajo de cambio de esquema, Milvus elimina la función, su campo vectorial generado y el índice asociado de forma conjunta, al tiempo que conserva los campos de entrada de la función.

¿Tengo que esperar después de modificar el esquema de una colección?

Normalmente, no es necesario esperar manualmente. Si tu siguiente operación depende del esquema actualizado, puedes llamar primero a ` describe_collection() ` para confirmar el esquema que Milvus devuelve actualmente.

En una implementación distribuida, puede haber un breve intervalo de propagación mientras los componentes de Milvus actualizan los metadatos de la colección. Si una operación realizada inmediatamente después del cambio de esquema falla con un error relacionado con el esquema, actualiza el esquema y vuelve a intentar la operación.

¿Cuándo se recupera el espacio de almacenamiento tras eliminar un campo?

Al eliminar un campo, este se suprime del esquema actual y deja de ser visible en las consultas y búsquedas normales, pero los datos históricos de ese campo no se eliminan físicamente del almacenamiento de objetos de forma inmediata.

El espacio de almacenamiento se puede recuperar más tarde durante la compactación. La compactación es un proceso en segundo plano que reorganiza los archivos de datos existentes en archivos nuevos y más compactos. Una vez eliminado un campo, los archivos recién compactados siguen el esquema actual y omiten el campo eliminado. Milvus no garantiza una reducción inmediata ni en un plazo fijo del espacio de almacenamiento tras eliminar un campo.

¿Qué ocurre si añado un campo escalar con el mismo nombre que una clave de campo dinámico?

Si el campo dinámico está habilitado, puedes añadir un campo escalar con el mismo nombre que una clave de campo dinámico existente. El nuevo campo escalar enmascara la clave del campo dinámico en la salida normal de la consulta, pero los datos dinámicos originales se conservan en $meta.

Por ejemplo, si las entidades existentes almacenan una clave dinámica denominada source y, posteriormente, se añade un campo escalar denominado source, la salida normal de source hará referencia al campo escalar. Para acceder al valor dinámico original, utilice la sintaxis de ruta $meta, como por ejemplo $meta["source"].