Partilhar via


Definindo seu esquema de armazenamento usando uma definição de registro (Visualização)

Aviso

A funcionalidade Semantic Kernel Vetor Store está em pré-visualização, e melhorias que exigem alterações de quebra ainda podem ocorrer em circunstâncias limitadas antes do lançamento.

Descrição geral

Os conectores do Semantic Kernel Vetor Store usam uma abordagem de modelo inicial para interagir com bancos de dados e permitem anotar modelos de dados com informações necessárias para criar índices ou mapear dados para o esquema de banco de dados.

Outra forma de fornecer essas informações é por meio de definições de registro, que podem ser definidas e fornecidas separadamente ao modelo de dados. Isso pode ser útil em vários cenários:

  • Pode haver um caso em que um desenvolvedor queira usar o mesmo modelo de dados com mais de uma configuração.
  • Pode haver um caso em que o desenvolvedor deseja armazenar dados usando um esquema muito diferente do modelo e deseja fornecer um mapeador personalizado para conversão entre o modelo de dados e o esquema de armazenamento.
  • Pode haver um caso em que um desenvolvedor queira usar um tipo interno, como um dict, ou um formato otimizado, como um dataframe e ainda queira aproveitar a funcionalidade de armazenamento vetorial.

Aqui está um exemplo de como criar uma definição de registro.

using Microsoft.Extensions.VectorData;

var hotelDefinition = new VectorStoreRecordDefinition
{
    Properties = new List<VectorStoreRecordProperty>
    {
        new VectorStoreRecordKeyProperty("HotelId", typeof(ulong)),
        new VectorStoreRecordDataProperty("HotelName", typeof(string)) { IsFilterable = true },
        new VectorStoreRecordDataProperty("Description", typeof(string)) { IsFullTextSearchable = true },
        new VectorStoreRecordVectorProperty("DescriptionEmbedding", typeof(float)) { Dimensions = 4, DistanceFunction = DistanceFunction.CosineDistance, IndexKind = IndexKind.Hnsw },
    }
};

Ao criar uma definição, você sempre precisa fornecer um nome e um tipo para cada propriedade em seu esquema, pois isso é necessário para a criação de índice e mapeamento de dados.

Para usar a definição, passe-a para o método GetCollection.

var collection = vectorStore.GetCollection<ulong, Hotel>("skhotels", hotelDefinition);

Classes de configuração da propriedade de registro

VectorStoreRecordKeyProperty

Use essa classe para indicar que sua propriedade é a chave do registro.

new VectorStoreRecordKeyProperty("HotelId", typeof(ulong)),

Definições de configuração de VectorStoreRecordKeyProperty

Parâmetro Necessário Description
DataModelPropertyName Sim O nome da propriedade no modelo de dados. Usado pelos mapeadores integrados para mapear automaticamente entre o esquema de armazenamento e o modelo de dados e para criar índices.
Tipo de propriedade Sim O tipo da propriedade no modelo de dados. Usado pelos mapeadores integrados para mapear automaticamente entre o esquema de armazenamento e o modelo de dados e para criar índices.
StoragePropertyName Não Pode ser usado para fornecer um nome alternativo para a propriedade no banco de dados. Note que este parâmetro não é suportado por todos os conectores, por exemplo, onde alternativas como JsonPropertyNameAttribute é suportado.

Gorjeta

Para obter mais informações sobre quais conectores suportam StoragePropertyName e quais alternativas estão disponíveis, consulte a documentação de cada conector.

VectorStoreRecordDataProperty

Use essa classe para indicar que sua propriedade contém dados gerais que não são uma chave ou um vetor.

new VectorStoreRecordDataProperty("HotelName", typeof(string)) { IsFilterable = true },

Definições de configuração de VectorStoreRecordDataProperty

Parâmetro Necessário Description
DataModelPropertyName Sim O nome da propriedade no modelo de dados. Usado pelos mapeadores integrados para mapear automaticamente entre o esquema de armazenamento e o modelo de dados e para criar índices.
Tipo de propriedade Sim O tipo da propriedade no modelo de dados. Usado pelos mapeadores integrados para mapear automaticamente entre o esquema de armazenamento e o modelo de dados e para criar índices.
IsFilterable Não Indica se a propriedade deve ser indexada para filtragem nos casos em que um banco de dados requer a aceitação da indexação por propriedade. A predefinição é falsa.
IsFullTextSearchable Não Indica se a propriedade deve ser indexada para pesquisa de texto completo para bancos de dados que oferecem suporte à pesquisa de texto completo. A predefinição é falsa.
StoragePropertyName Não Pode ser usado para fornecer um nome alternativo para a propriedade no banco de dados. Note que este parâmetro não é suportado por todos os conectores, por exemplo, onde alternativas como JsonPropertyNameAttribute é suportado.

Gorjeta

Para obter mais informações sobre quais conectores suportam StoragePropertyName e quais alternativas estão disponíveis, consulte a documentação de cada conector.

VectorStoreRecordVectorProperty

Use essa classe para indicar que sua propriedade contém um vetor.

new VectorStoreRecordVectorProperty("DescriptionEmbedding", typeof(float)) { Dimensions = 4, DistanceFunction = DistanceFunction.CosineDistance, IndexKind = IndexKind.Hnsw },

Definições de configuração de VectorStoreRecordVectorProperty

Parâmetro Necessário Description
DataModelPropertyName Sim O nome da propriedade no modelo de dados. Usado pelos mapeadores integrados para mapear automaticamente entre o esquema de armazenamento e o modelo de dados e para criar índices.
Tipo de propriedade Sim O tipo da propriedade no modelo de dados. Usado pelos mapeadores integrados para mapear automaticamente entre o esquema de armazenamento e o modelo de dados e para criar índices.
Dimensões Sim para criar coleção, opcional caso contrário O número de dimensões que o vetor tem. Isso geralmente é necessário ao criar um índice de vetor para uma coleção.
IndexKind Não O tipo de índice com o qual indexar o vetor. O padrão varia de acordo com o tipo de armazenamento vetorial.
Função DistânciaDistância Não O tipo de função de distância a ser usada ao fazer a comparação vetorial durante a pesquisa vetorial sobre esse vetor. O padrão varia de acordo com o tipo de armazenamento vetorial.
StoragePropertyName Não Pode ser usado para fornecer um nome alternativo para a propriedade no banco de dados. Note que este parâmetro não é suportado por todos os conectores, por exemplo, onde alternativas como JsonPropertyNameAttribute é suportado.

Gorjeta

Para obter mais informações sobre quais conectores suportam StoragePropertyName e quais alternativas estão disponíveis, consulte a documentação de cada conector.

Aqui está um exemplo de como criar uma definição de registro, para uso com um DataFrame pandas.

Nota

Os mesmos campos que na definição do modelo de dados são usados aqui, para um modelo de dados eles são adicionados como anotações, aqui como um ditado com o nome.

Há algumas coisas importantes a observar, além das próprias definições de campos. O primeiro é o container_mode parâmetro. Quando definido como True, isso indica que o modelo de dados é um tipo de contêiner, como um DataFrame, e que o modelo de dados é, portanto, um contêiner de registros, em vez de um único, um registro de contêiner pode ser usado exatamente da mesma maneira, a principal diferença é que get e get_batch retornará o mesmo tipo de dados, com um único registo para um get e um ou mais para um get_batch. Quando você quer fazer um upsert, upsert e upsert_batch pode ser usado de forma intercambiável, em outras palavras, passar um contêiner para upsert resultará em vários upserts, em vez de um único.

O segundo é a adição dos métodos andfrom_dict, que são usados para converter entre o modelo de dados e o esquema de to_dict armazenamento. Nesse caso, o to_dict método é usado para converter o DataFrame em uma lista de registros, e o from_dict método é usado para converter uma lista de registros em um DataFrame. Também pode haver um serialize método e deserialize (não mostrado no exemplo abaixo), para obter detalhes sobre a diferença entre eles, consulte a documentação de serialização.

from semantic_kernel.data import (
    VectorStoreRecordDataField,
    VectorStoreRecordDefinition,
    VectorStoreRecordKeyField,
    VectorStoreRecordVectorField,
)

hotel_definition = VectorStoreRecordDefinition(
    fields={
        "hotel_id": VectorStoreRecordKeyField(property_type="str"),
        "hotel_name": VectorStoreRecordDataField(property_type="str", is_filterable=True),
        "description": VectorStoreRecordDataField(
            property_type="str", has_embedding=True, embedding_property_name="description_embedding"
        ),
        "description_embedding": VectorStoreRecordVectorField(property_type="list[float]"),
    },
    container_mode=True,
    to_dict=lambda record, **_: record.to_dict(orient="records"),
    from_dict=lambda records, **_: DataFrame(records),
)

Ao criar uma definição, você sempre precisa fornecer um nome (como a chave no fields ditado) e digitar para cada propriedade em seu esquema, já que isso é necessário para a criação de índice e mapeamento de dados.

Para usar a definição, passe-a para o método GetCollection ou um construtor de coleção, juntamente com o tipo de modelo de dados.

collection = vector_store.get_collection(
    collection_name="skhotels", 
    data_model_type=pd.DataFrame, 
    data_model_definition=hotel_definition,
)

Aqui está um exemplo de como criar uma definição de registro.

var hotelDefinition = VectorStoreRecordDefinition.fromFields(
    Arrays.asList(
        VectorStoreRecordKeyField.builder().withName("hotelId").withFieldType(String.class).build(),
        VectorStoreRecordDataField.builder()
            .withName("name")
            .withFieldType(String.class)
            .isFilterable(true).build(),
        VectorStoreRecordDataField.builder()
            .withName("description")
            .withFieldType(String.class)
            .isFullTextSearchable(true).build(),
        VectorStoreRecordVectorField.builder().withName("descriptionEmbedding")
            .withDimensions(4)
            .withIndexKind(IndexKind.HNSW)
            .withDistanceFunction(DistanceFunction.COSINE_DISTANCE)
            .withFieldType(List.class).build()
    )
);

Ao criar uma definição, você sempre precisa fornecer um nome e um tipo para cada campo em seu esquema, pois isso é necessário para a criação de índice e mapeamento de dados.

Para usar a definição, passe-a para o método GetCollection.

var collection = vectorStore.getCollection("skhotels",
        JDBCVectorStoreRecordCollectionOptions.builder()
            .withRecordDefinition(hotelDefinition)
            .build()
    );

Classes de configuração do campo de registro

VectorStoreRecordKeyField

Use essa classe para indicar que seu campo é a chave do registro.

VectorStoreRecordKeyField.builder().withName("hotelId").withFieldType(String.class).build(),

Definições de configuração de VectorStoreRecordKeyField

Parâmetro Necessário Description
nome Sim O nome do campo no modelo de dados. Usado pelos mapeadores integrados para mapear automaticamente entre o esquema de armazenamento e o modelo de dados e para criar índices.
Tipo de campo Sim O tipo do campo no modelo de dados. Usado pelos mapeadores integrados para mapear automaticamente entre o esquema de armazenamento e o modelo de dados e para criar índices.
nome_do_armazenamento Não Pode ser usado para fornecer um nome alternativo para o campo no banco de dados. Observe que este parâmetro não é suportado por todos os conectores, por exemplo, onde Jackson é usado, nesse caso, o nome do armazenamento pode ser especificado usando anotações Jackson.

Gorjeta

Para obter mais informações sobre quais conectores suportam storageName e quais alternativas estão disponíveis, consulte a documentação de cada conector.

VectorStoreRecordDataField

Use essa classe para indicar que sua propriedade contém dados gerais que não são uma chave ou um vetor.

VectorStoreRecordDataField.builder()
    .withName("name")
    .withFieldType(String.class)
    .isFilterable(true).build(),

Definições de configuração de VectorStoreRecordDataField

Parâmetro Necessário Description
nome Sim O nome do campo no modelo de dados. Usado pelos mapeadores integrados para mapear automaticamente entre o esquema de armazenamento e o modelo de dados e para criar índices.
Tipo de campo Sim O tipo do campo no modelo de dados. Usado pelos mapeadores integrados para mapear automaticamente entre o esquema de armazenamento e o modelo de dados e para criar índices.
isFiltrável Não Indica se o campo deve ser indexado para filtragem nos casos em que um banco de dados requer a aceitação da indexação por campo. A predefinição é falsa.
isFullTextSearchable Não Indica se o campo deve ser indexado para pesquisa de texto completo para bancos de dados que suportam pesquisa de texto completo. A predefinição é falsa.
nome_do_armazenamento Não Pode ser usado para fornecer um nome alternativo para o campo no banco de dados. Observe que este parâmetro não é suportado por todos os conectores, por exemplo, onde Jackson é usado, nesse caso, o nome do armazenamento pode ser especificado usando anotações Jackson.

Gorjeta

Para obter mais informações sobre quais conectores suportam storageName e quais alternativas estão disponíveis, consulte a documentação de cada conector.

VectorStoreRecordVectorField

Use essa classe para indicar que seu campo contém um vetor.

VectorStoreRecordVectorField.builder().withName("descriptionEmbedding")
    .withDimensions(4)
    .withIndexKind(IndexKind.HNSW)
    .withDistanceFunction(DistanceFunction.COSINE_DISTANCE)
    .withFieldType(List.class).build(),

Definições de configuração de VectorStoreRecordVectorField

Parâmetro Necessário Description
nome Sim O nome do campo no modelo de dados. Usado pelos mapeadores integrados para mapear automaticamente entre o esquema de armazenamento e o modelo de dados e para criar índices.
Tipo de campo Sim O tipo do campo no modelo de dados. Usado pelos mapeadores integrados para mapear automaticamente entre o esquema de armazenamento e o modelo de dados e para criar índices.
dimensões Sim para criar coleção, opcional caso contrário O número de dimensões que o vetor tem. Isso geralmente é necessário ao criar um índice de vetor para uma coleção.
indexKind Não O tipo de índice com o qual indexar o vetor. O padrão varia de acordo com o tipo de armazenamento vetorial.
distanceFunction Não O tipo de função de distância a ser usada ao fazer a comparação vetorial durante a pesquisa vetorial sobre esse vetor. O padrão varia de acordo com o tipo de armazenamento vetorial.
nome_do_armazenamento Não Pode ser usado para fornecer um nome alternativo para o campo no banco de dados. Observe que este parâmetro não é suportado por todos os conectores, por exemplo, onde Jackson é usado, nesse caso, o nome do armazenamento pode ser especificado usando anotações Jackson.

Gorjeta

Para obter mais informações sobre quais conectores suportam storageName e quais alternativas estão disponíveis, consulte a documentação de cada conector.