Compartilhar via


Propriedades computadas no Azure Cosmos DB for NoSQL

APLICA-SE A: NoSQL

As propriedades computadas no Azure Cosmos DB têm valores derivados de propriedades de item existentes, mas não são persistentes nos próprios itens. Propriedades computadas têm como escopo um único item e podem ser referenciadas em consultas como se fossem propriedades persistentes. As propriedades computadas facilitam a gravação de lógica de consulta complexa uma vez e fazem referência a ela muitas vezes. Você pode adicionar um único índice nessas propriedades ou usá-las como parte de um índice composto para melhorar o desempenho.

Observação

Você tem algum comentário sobre propriedades computadas? Queremos saber sua opinião! Sinta-se à vontade para compartilhar comentários diretamente com a equipe de engenharia do Azure Cosmos DB: cosmoscomputedprops@microsoft.com.

O que é uma propriedade computada?

As propriedades computadas devem estar no nível superior do item e não podem ter um caminho aninhado. Cada definição de propriedade computada tem dois componentes: um nome e uma consulta. O nome é o nome da propriedade computada e a consulta define a lógica para calcular o valor da propriedade de cada item. As propriedades computadas têm como escopo um item individual e, portanto, não podem usar valores de vários itens ou depender de outras propriedades computadas. Cada contêiner pode ter no máximo 20 propriedades computadas.

Exemplo de definição de propriedade computada:

{
  "computedProperties": [
    {
      "name": "cp_lowerName",
      "query": "SELECT VALUE LOWER(c.name) FROM c"
    }
  ]
}

Restrições de nome

É altamente recomendável nomear propriedades computadas para que não haja colisão com um nome de propriedade persistente. Para evitar nomes sobrepostos de propriedade, você pode adicionar um prefixo ou sufixo a todos os nomes de propriedade computada. Este artigo usa o prefixo cp_ em todas as definições de nome.

Importante

A definição de uma propriedade computada com o mesmo nome de uma propriedade persistente não irá gerar um erro, mas pode causar um comportamento inesperado. Não importa se a propriedade computada está indexada, os valores das propriedades persistentes que compartilham um nome com uma propriedade computada não serão incluídos no índice. As consultas sempre usarão a propriedade computada em vez da propriedade persistente, com exceção da propriedade persistente que está sendo retornada em vez da propriedade computada se houver uma projeção curinga na cláusula SELECT. A projeção curinga não inclui automaticamente as propriedades computadas.

As restrições nos nomes de propriedade computada são:

  • Todas as propriedades computadas devem ter nomes exclusivos.
  • O valor da propriedade name representa o nome da propriedade de nível superior que pode ser usada para fazer referência à propriedade computada.
  • Nomes de propriedades reservadas do sistema, como id, _rid e _ts não podem ser usados como nomes de propriedade computada.
  • Um nome de propriedade computada não pode corresponder a um caminho de propriedade já indexado. Essa restrição se aplica a todos os caminhos de indexação especificados, incluindo:
    • Caminhos incluídos
    • Caminhos excluídos
    • Índices espaciais
    • Índices compostos

Restrições de consultas

As consultas na definição de propriedade computada devem ser válidas sintaticamente e semanticamente, caso contrário, a operação de criação ou atualização falha. As consultas devem ser avaliadas como um valor determinístico para todos os itens em um contêiner. As consultas podem ser avaliadas como indefinidas ou nulas para alguns itens, e as propriedades computadas com valores indefinidos ou nulos se comportam da mesma forma que as propriedades persistentes com valores indefinidos ou nulos quando usadas em consultas.

As limitações nas definições de consulta de propriedade computada são:

  • As consultas devem especificar uma cláusula FROM que representa a referência de item raiz. Exemplos de cláusulas FROM com suporte são: FROM c, FROM root c e FROM MyContainer c.
  • As consultas devem usar uma cláusula VALUE na projeção.
  • As consultas não podem incluir um JOIN.
  • As consultas não podem usar expressões escalares não determinísticas. Exemplos de expressões escalares não determinísticas são: GetCurrentDateTime, GetCurrentTimeStamp, GetCurrentTicks e RAND.
  • As consultas não podem usar nenhuma das seguintes cláusulas: WHERE, GROUP BY, ORDER BY, TOP, DISTINCT, OFFSET LIMIT, EXISTS, ALL, LAST, FIRST e NONE.
  • As consultas não podem incluir uma subconsulta escalar.
  • Não há suporte para funções de agregação, funções espaciais, funções não determinísticas e UDFs (funções definidas pelo usuário).

Criando propriedades computadas

Depois que as propriedades computadas forem criadas, você poderá executar consultas que fazem referência às propriedades usando qualquer método, incluindo todos os SDKs (kits de desenvolvimento de software) e o Azure Data Explorer no portal do Azure.

Versão compatível Observações
SDK v3 do .NET >= 3.34.0-preview No momento, as propriedades computadas só estão disponíveis em versões de pacote de visualização.
SDK do Java v4 >= 4.46.0 As propriedades computadas estão atualmente em versão prévia.
SDK do Python >= v4.5.2b5 As propriedades computadas estão atualmente em versão prévia.

Criar propriedades computadas usando o SDK

Você pode criar um novo contêiner com propriedades computadas definidas ou adicioná-las a um contêiner existente.

Veja a seguir um exemplo de como criar propriedades computadas em um novo contêiner:

ContainerProperties containerProperties = new ContainerProperties("myContainer", "/pk")
{
    ComputedProperties = new Collection<ComputedProperty>
    {
        new ComputedProperty
        {
            Name = "cp_lowerName",
            Query = "SELECT VALUE LOWER(c.name) FROM c"
        }
    }
};

Container container = await client.GetDatabase("myDatabase").CreateContainerAsync(containerProperties);

Veja a seguir um exemplo de como atualizar propriedades computadas em um contêiner existente:

var container = client.GetDatabase("myDatabase").GetContainer("myContainer");

// Read the current container properties
var containerProperties = await container.ReadContainerAsync();
// Make the necessary updates to the container properties
containerProperties.Resource.ComputedProperties = new Collection<ComputedProperty>
    {
        new ComputedProperty
        {
            Name = "cp_lowerName",
            Query = "SELECT VALUE LOWER(c.name) FROM c"
        },
        new ComputedProperty
        {
            Name = "cp_upperName",
            Query = "SELECT VALUE UPPER(c.name) FROM c"
        }
    };
// Update the container with changes
await container.ReplaceContainerAsync(containerProperties);

Dica

Sempre que você atualiza as propriedades do contêiner, os valores antigos são substituídos. Se você tiver propriedades computadas existentes e quiser adicionar novas, adicione propriedades computadas novas e existentes à coleção.

Criar propriedades computadas usando o Data Explorer

Você pode usar o Data Explorer para criar uma propriedade computada para um contêiner.

  1. Abra o contêiner existente no Data Explorer.

  2. Navegue até a seção Configurações do seu contêiner. Em seguida, navegue até a subseção *Propriedades Computadas.

  3. Edite o JSON de definição de propriedades computadas para seu contêiner. Neste exemplo, esse JSON é usado para definir uma propriedade computada para dividir a SKU cadeia de caracteres de um produto de varejo usando o - delimitador.

    [
      {
        "name": "cp_splitSku",
        "query": "SELECT VALUE StringSplit(p.sku, \"-\") FROM products p"
      }
    ]
    

    Captura de tela do editor JSON de propriedades computadas na interface do Data Explorer.

  4. Salve a propriedade computada.

Use propriedades computadas em consultas

As propriedades computadas podem ser referenciadas em consultas da mesma forma que as propriedades persistentes. Os valores das propriedades computadas que não são indexadas são avaliados durante o runtime usando a definição de propriedade computada. Se uma propriedade computada for indexada, o índice será usado da mesma maneira que ocorre nas propriedades persistentes e a propriedade computada será avaliada conforme necessário. É recomendável adicionar índices às suas propriedades computadas para obter o melhor custo e desempenho.

Os exemplos a seguir usam o conjunto de dados de produtos de início rápido que está disponível no Data Explorer no portal do Azure. Para começar, selecione Inicialização do início rápido e carregar o conjunto de dados em um novo contêiner.

Captura de tela que ilustra como carregar um conjunto de dados de exemplo em um banco de dados e contêiner.

Aqui está um exemplo de um item:

{
  "id": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb",
  "categoryId": "bbbbbbbb-1111-2222-3333-cccccccccccc",
  "categoryName": "Bikes, Touring Bikes",
  "sku": "BK-T79U-50",
  "name": "Touring-1000 Blue, 50",
  "description": "The product called \"Touring-1000 Blue, 50\"",
  "price": 2384.07,
  "tags": [
    {
      "id": "cccccccc-2222-3333-4444-dddddddddddd",
      "name": "Tag-61"
    }
  ],
  "_rid": "n7AmAPTJ480GAAAAAAAAAA==",
  "_self": "dbs/n7AmAA==/colls/n7AmAPTJ480=/docs/n7AmAPTJ480GAAAAAAAAAA==/",
  "_etag": "\"01002683-0000-0800-0000-6451fb4b0000\"",
  "_attachments": "attachments/",
  "_ts": 1683094347
}

Projeção

Se as propriedades computadas precisarem ser projetadas, elas deverão ser referenciadas explicitamente. Projeções curinga como SELECT * retornam todas as propriedades persistentes, mas não incluem propriedades computadas.

Aqui está um exemplo de definição de propriedade computada para converter a propriedade name em minúsculas:

{ 
  "name": "cp_lowerName", 
  "query": "SELECT VALUE LOWER(c.name) FROM c" 
} 

Essa propriedade pode ser projetada em uma consulta:

SELECT 
    c.cp_lowerName 
FROM 
    c

cláusula WHERE

As propriedades computadas podem ser referenciadas em predicados de filtro, como quaisquer propriedades persistentes. É recomendável adicionar índices únicos ou compostos que sejam relevantes ao usar propriedades computadas em filtros.

Aqui está um exemplo de definição de propriedade computada para calcular um desconto de 20% no preço:

{ 
  "name": "cp_20PercentDiscount", 
  "query": "SELECT VALUE (c.price * 0.2) FROM c" 
} 

Essa propriedade poderia então ser filtrada para garantir que apenas os produtos com desconto inferior a US$ 50 sejam retornados:

SELECT 
    c.price - c.cp_20PercentDiscount as discountedPrice, 
    c.name 
FROM 
    c 
WHERE 
    c.cp_20PercentDiscount < 50.00

Cláusula GROUP BY

Assim como ocorre com as propriedades persistentes, as propriedades computadas podem ser referenciadas na cláusula GROUP BY e usar o índice sempre que possível. Para obter o melhor desempenho, adicione índices únicos ou compostos que sejam relevantes.

Aqui está um exemplo de definição de propriedade computada que localiza a categoria primária para cada item da propriedade categoryName:

{
  "name": "cp_primaryCategory",
  "query": "SELECT VALUE SUBSTRING(c.categoryName, 0, INDEX_OF(c.categoryName, ',')) FROM c"
}

Em seguida, você pode agrupar por cp_primaryCategory para obter a contagem de itens em cada categoria primária:

SELECT 
    COUNT(1), 
    c.cp_primaryCategory 
FROM 
    c 
GROUP BY 
    c.cp_primaryCategory

Dica

Embora você também possa obter essa consulta sem usar propriedades computadas, o uso das propriedades computadas simplifica bastante a gravação da consulta e permite um desempenho melhor porque cp_primaryCategory pode ser indexado. SUBSTRING() e INDEX_OF() exigem um exame completo de todos os itens no contêiner, mas se você indexar a propriedade computada, a consulta inteira poderá ser atendida do índice. A capacidade de atender à consulta do índice em vez de depender de um exame completo aumenta o desempenho e reduz os custos de RU da consulta.

Cláusula ORDER BY

Assim como ocorre com as propriedades persistentes, as propriedades computadas podem ser referenciadas na cláusula ORDER BY e precisam ser indexadas para que a consulta tenha êxito. Usando propriedades computadas, você pode ORDER BY o resultado de lógica complexa ou funções do sistema, o que abre muitos novos cenários de consulta usando o Azure Cosmos DB.

Aqui está um exemplo de definição de propriedade computada que obtém o mês do valor _ts:

{
  "name": "cp_monthUpdated",
  "query": "SELECT VALUE DateTimePart('m', TimestampToDateTime(c._ts*1000)) FROM c"
}

Antes de ORDER BY cp_monthUpdated, você deve adicioná-la à política de indexação. Depois que a política de indexação for atualizada, você poderá ordenar pela propriedade computada.

SELECT
    *
FROM
    c
ORDER BY
    c.cp_monthUpdated

Indexar propriedades computadas

As propriedades computadas não são indexadas por padrão e não são cobertas por caminhos curinga na política de indexação. Você pode adicionar índices únicos ou compostos em propriedades computadas na política de indexação da mesma forma que adicionaria índices em propriedades persistentes. Recomendamos que você adicione índices relevantes a todas as propriedades computadas. Recomendamos esses índices porque eles são benéficos para aumentar o desempenho e reduzir as RUs (unidades de solicitação). Quando as propriedades computadas são indexadas, os valores reais são avaliados durante operações de gravação de item para gerar e persistir termos de índice.

Há algumas considerações para indexar propriedades computadas, incluindo:

  • As propriedades computadas podem ser especificadas em caminhos incluídos, caminhos excluídos e caminhos de índice composto
  • As propriedades computadas não podem ter um índice espacial definido nelas
  • Os caminhos curinga no caminho da propriedade computada funcionam como para propriedades regulares
  • Os índices relacionados em uma propriedade removida e indexada também devem ser descartados

Observação

Todas as propriedades computadas são definidas no nível superior do item. O caminho é sempre /<computed property name>.

Dica

Sempre que você atualiza as propriedades do contêiner, os valores antigos são substituídos. Se você tiver propriedades computadas existentes e quiser adicionar novas, adicione propriedades computadas novas e existentes à coleção.

Observação

Quando a definição de uma propriedade computada indexada é modificada, ela não é reindexada automaticamente. Para indexar a propriedade computada modificada, primeiro você precisará remover a propriedade computada do índice. Depois que o reindexação for concluído, adicione a propriedade computada de volta à política de índice.

Se você quiser excluir uma propriedade computada, primeiro precisará removê-la da política de índice.

Adicionar um único índice a propriedades computadas

Para adicionar um único índice a uma propriedade computada nomeada cp_myComputedProperty:

{
  "indexingMode": "consistent",
  "automatic": true,
  "includedPaths": [
    {
      "path": "/*"
    },
    {
      "path": "/cp_myComputedProperty/?"
    }
  ],
  "excludedPaths": [
    {
      "path": "/\"_etag\"/?"
    }
  ]
}

Adicionar um índice composto a propriedades computadas

Para adicionar um índice composto em duas propriedades nas quais uma é computada como cp_myComputedPropertye a outra persiste como myPersistedProperty:

{
  "indexingMode": "consistent",
  "automatic": true,
  "includedPaths": [
    {
      "path": "/*"
    }
  ],
  "excludedPaths": [
    {
      "path": "/\"_etag\"/?"
    }
  ],
  "compositeIndexes": [
    [
      {
        "path": "/cp_myComputedProperty"
      },
      {
        "path": "/path/to/myPersistedProperty"
      }
    ]
  ]
}

Entender o consumo da unidade de solicitação

A adição de propriedades computadas a um contêiner não consome RUs. As operações de gravação em contêineres que têm propriedades computadas definidas podem ter um pequeno aumento de RU. Se uma propriedade computada for indexada, as RUs em operações de gravação aumentarão para refletir os custos de indexação e avaliação da propriedade computada.