DynamoDB - Yerel İkincil Dizinler

Bazı uygulamalar yalnızca birincil anahtarla sorgu gerçekleştirir, ancak bazı durumlarda alternatif bir sıralama anahtarından yararlanır. Tek veya birden çok yerel ikincil dizin oluşturarak uygulamanıza bir seçim izni verin.

Milyonlarca öğenin taranması gibi karmaşık veri erişim gereksinimleri, daha verimli sorgu / taramaların gerçekleştirilmesini gerekli kılar. Yerel ikincil dizinler, bölüm anahtarı değeri için alternatif bir sıralama anahtarı sağlar. Ayrıca tüm veya bazı tablo niteliklerinin kopyalarını da tutarlar. Verileri tablo bölüm anahtarına göre düzenlerler, ancak farklı bir sıralama anahtarı kullanırlar.

Yerel bir ikincil dizin kullanmak, tüm tablo taraması ihtiyacını ortadan kaldırır ve bir sıralama anahtarı kullanarak basit ve hızlı bir sorguya izin verir.

Tüm yerel ikincil dizinler belirli koşulları karşılamalıdır -

  • Özdeş bölüm anahtarı ve kaynak tablo bölüm anahtarı.
  • Yalnızca bir skaler özniteliğin sıralama anahtarı.
  • Anahtar olmayan bir özellik olarak hareket eden kaynak tablo sıralama anahtarının projeksiyonu.

Tüm yerel ikincil dizinler otomatik olarak bölümü tutar ve anahtarları üst tablolardan sıralar. Sorgularda bu, öngörülen özniteliklerin verimli bir şekilde toplanması ve ayrıca öngörülemeyen özniteliklerin alınması anlamına gelir.

Yerel bir ikincil dizin için depolama sınırı, tüm tablo öğelerini ve bir bölüm anahtarı değerini paylaşan dizin öğelerini içeren bölüm anahtarı değeri başına 10 GB olarak kalır.

Bir Öznitelik Yansıtma

Bazı işlemler, karmaşıklık nedeniyle fazla okuma / getirme gerektirir. Bu işlemler önemli miktarda iş hacmi tüketebilir. Projeksiyon, bu öznitelikleri izole ederek yüksek maliyetli getirmekten kaçınmanıza ve zengin sorgular gerçekleştirmenize olanak tanır. Tahminlerin ikincil bir dizine kopyalanmış özniteliklerden oluştuğunu unutmayın.

İkincil bir dizin oluştururken, öngörülen öznitelikleri belirtirsiniz. DynamoDB tarafından sağlanan üç seçeneği hatırlayın:KEYS_ONLY, INCLUDE, and ALL.

Projeksiyonda belirli özellikleri seçerken, ilişkili maliyet değiş tokuşlarını göz önünde bulundurun -

  • Yalnızca küçük bir dizi gerekli öznitelik yansıtırsanız, depolama maliyetlerini önemli ölçüde azaltırsınız.

  • Sık erişilen anahtar olmayan özellikleri yansıtırsanız, tarama maliyetlerini depolama maliyetleriyle dengelersiniz.

  • Anahtar olmayan özniteliklerin çoğunu veya tamamını yansıtırsanız, bu esnekliği en üst düzeye çıkarır ve verimi azaltır (alma olmaz); ancak depolama maliyetleri yükselir.

  • KEYS_ONLY'i sık yazma / güncelleme ve seyrek sorgular için yansıtırsanız, boyutu en aza indirir, ancak sorgu hazırlığını sürdürür.

Yerel İkincil Endeks Oluşturma

Kullan LocalSecondaryIndexTek veya birden çok yerel ikincil dizin oluşturmak için CreateTable parametresini kullanın. Sıralama anahtarı için anahtar olmayan bir öznitelik belirtmelisiniz. Tablo oluştururken yerel ikincil endeksler oluşturursunuz. Silme işlemi sırasında bu dizinleri de silersiniz.

Yerel ikincil dizine sahip tablolar, bölüm anahtarı değeri başına boyut olarak 10 GB sınırına uymalıdır, ancak herhangi bir miktarda öğe depolayabilir.

Yerel İkincil Dizin Sorguları ve Taramaları

Yerel ikincil dizinler üzerindeki bir sorgu işlemi, dizindeki birden çok öğe sıralama anahtarı değerleri paylaştığında eşleşen bir bölüm anahtarı değerine sahip tüm öğeleri döndürür. Eşleşen öğeler belirli bir sırayla geri dönmez. Yerel ikincil dizinler için sorgular, en son değerleri sağlayan son derece tutarlı okumalar ile nihai veya güçlü tutarlılık kullanır.

Tarama işlemi, tüm yerel ikincil dizin verilerini döndürür. Taramalar, bir tablo ve dizin adı sağlamanızı ve verileri atmak için bir filtre ifadesinin kullanılmasına izin vermenizi gerektirir.

Öğe Yazma

Yerel bir ikincil dizin oluştururken, bir sıralama anahtarı özniteliğini ve veri türünü belirtirsiniz. Bir öğe yazdığınızda, öğe bir dizin anahtarının özniteliğini tanımlıyorsa, türünün anahtar şemasının veri türüyle eşleşmesi gerekir.

DynamoDB, tablo öğelerine ve yerel ikincil dizin öğelerine bire bir ilişki gereksinimi getirmez. Birden çok yerel ikincil dizine sahip tablolar, daha az olanlara göre daha yüksek yazma maliyetleri taşır.

Yerel İkincil Dizinlerde Aktarım Hızı ile İlgili Hususlar

Bir sorgunun okuma kapasitesi tüketimi, veri erişiminin niteliğine bağlıdır. Sorgular ya nihai ya da güçlü tutarlılığı kullanır; sonuçta tutarlı okumalarda yarım birimle karşılaştırıldığında bir birim kullanarak son derece tutarlı okumalar kullanılır.

Sonuç sınırlamaları maksimum 1MB boyutunu içerir. Sonuç boyutları, en yakın 4KB'ye yuvarlanmış eşleşen dizin öğesi boyutunun ve en yakın 4KB'ye yuvarlanmış eşleşen tablo öğesi boyutunun toplamından gelir.

Yazma kapasitesi tüketimi, sağlanan birimler içinde kalır. Tablo yazımında tüketilen birimlerin ve endekslerin güncellenmesinde tüketilen birimlerin toplamını bularak toplam tedarik edilen maliyeti hesaplayın.

Maliyete etki eden temel faktörleri de göz önünde bulundurabilirsiniz, bunlardan bazıları -

  • Dizine alınmış bir özniteliği tanımlayan bir öğe yazdığınızda veya tanımlanmamış bir dizinlenmiş özniteliği tanımlamak için bir öğeyi güncellediğinizde, tek bir yazma işlemi gerçekleşir.

  • Bir tablo güncellemesi, dizinlenmiş bir anahtar öznitelik değerini değiştirdiğinde, iki yazma işlemi silinir ve ardından bir öğe eklenir.

  • Bir yazma, indekslenmiş bir özniteliğin silinmesine neden olduğunda, eski öğe projeksiyonunu kaldırmak için bir yazma gerçekleşir.

  • Bir güncellemeden önce veya sonra dizinde bir öğe yoksa, hiçbir yazma olmaz.

Yerel İkincil Dizin Depolama

Bir tablo öğesi yazma işleminde, DynamoDB doğru öznitelik kümesini gerekli yerel ikincil dizinlere otomatik olarak kopyalar. Bu, hesabınızı borçlandırır. Kullanılan alan, tablo birincil anahtar bayt boyutu, dizin anahtarı özniteliği bayt boyutu, herhangi bir mevcut öngörülen öznitelik bayt boyutu ve her dizin öğesi için ek yükteki 100 bayt toplamından kaynaklanır.

Tahmin deposu, ortalama indeks madde boyutu tahmin edilerek ve tablo madde miktarı ile çarpılarak elde edilir.

Yerel İkincil Dizinlerle Çalışmak için Java'yı Kullanma

Önce bir DynamoDB sınıfı örneği oluşturarak yerel bir ikincil dizin oluşturun. Ardından, gerekli istek bilgileriyle bir CreateTableRequest sınıfı örneği oluşturun. Son olarak, createTable yöntemini kullanın.

Misal

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient( 
   new ProfileCredentialsProvider()));
String tableName = "Tools";  
CreateTableRequest createTableRequest = new 
   CreateTableRequest().withTableName(tableName);
   
//Provisioned Throughput
createTableRequest.setProvisionedThroughput (
   new ProvisionedThroughput()
   .withReadCapacityUnits((long)5)
   .withWriteCapacityUnits(( long)5));
   
//Attributes 
ArrayList<AttributeDefinition> attributeDefinitions = 
   new ArrayList<AttributeDefinition>();
   attributeDefinitions.add(new AttributeDefinition()
   .withAttributeName("Make")
   .withAttributeType("S"));
   
attributeDefinitions.add(new AttributeDefinition()
   .withAttributeName("Model")
   .withAttributeType("S"));
   
attributeDefinitions.add(new AttributeDefinition()
   .withAttributeName("Line")
   .withAttributeType("S"));
   
createTableRequest.setAttributeDefinitions(attributeDefinitions);

//Key Schema 
ArrayList<KeySchemaElement> tableKeySchema = new 
   ArrayList<KeySchemaElement>();
   
tableKeySchema.add(new KeySchemaElement()
   .withAttributeName("Make")
   .withKeyType(KeyType.HASH));                    //Partition key
   
tableKeySchema.add(new KeySchemaElement()
   .withAttributeName("Model")
   .withKeyType(KeyType.RANGE));                   //Sort key
   
createTableRequest.setKeySchema(tableKeySchema);
ArrayList<KeySchemaElement> indexKeySchema = new 
   ArrayList<KeySchemaElement>();
   
indexKeySchema.add(new KeySchemaElement()
   .withAttributeName("Make")
   .withKeyType(KeyType.HASH));                   //Partition key
   
indexKeySchema.add(new KeySchemaElement()
   .withAttributeName("Line")
   .withKeyType(KeyType.RANGE));                   //Sort key
   
Projection projection = new Projection()
   .withProjectionType(ProjectionType.INCLUDE);

ArrayList<String> nonKeyAttributes = new ArrayList<String>(); 
nonKeyAttributes.add("Type"); 
nonKeyAttributes.add("Year"); 
projection.setNonKeyAttributes(nonKeyAttributes);  

LocalSecondaryIndex localSecondaryIndex = new LocalSecondaryIndex() 
   .withIndexName("ModelIndex")
   .withKeySchema(indexKeySchema)
   .withProjection(p rojection);  

ArrayList<LocalSecondaryIndex> localSecondaryIndexes = new 
   ArrayList<LocalSecondaryIndex>(); 

localSecondaryIndexes.add(localSecondaryIndex); 
createTableRequest.setLocalSecondaryIndexes(localSecondaryIndexes);  
Table table = dynamoDB.createTable(createTableRequest); 
System.out.println(table.getDescription());

Tanımlama yöntemiyle yerel bir ikincil dizin hakkındaki bilgileri alın. Basitçe bir DynamoDB sınıfı örneği oluşturun, bir Tablo sınıfı örneği oluşturun ve tabloyu açıklama yöntemine iletin.

Misal

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient( 
   new ProfileCredentialsProvider()));
   
String tableName = "Tools";
Table table = dynamoDB.getTable(tableName);
TableDescription tableDescription = table.describe();

List<LocalSecondaryIndexDescription> localSecondaryIndexes = 
   tableDescription.getLocalSecondaryIndexes();
   
Iterator<LocalSecondaryIndexDescription> lsiIter = 
   localSecondaryIndexes.iterator();
   
while (lsiIter.hasNext()) {  
   LocalSecondaryIndexDescription lsiDescription = lsiIter.next(); 
   System.out.println("Index info " + lsiDescription.getIndexName() + ":"); 
   Iterator<KeySchemaElement> kseIter = lsiDescription.getKeySchema().iterator(); 
   
   while (kseIter.hasNext()) { 
      KeySchemaElement kse = kseIter.next(); 
      System.out.printf("\t%s: %s\n", kse.getAttributeName(), kse.getKeyType()); 
   }
   
   Projection projection = lsiDescription.getProjection(); 
   System.out.println("\tProjection type: " + projection.getProjectionType()); 
   
   if (projection.getProjectionType().toString().equals("INCLUDE")) { 
      System.out.println("\t\tNon-key projected attributes: " + 
         projection.getNonKeyAttributes()); 
   } 
}

Tablo sorgusuyla aynı adımları kullanarak bir sorgu gerçekleştirin. Yalnızca bir DynamoDB sınıfı örneği, bir Tablo sınıfı örneği, bir Index sınıfı örneği, bir sorgu nesnesi oluşturun ve sorgu yöntemini kullanın.

Misal

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient( 
   new ProfileCredentialsProvider()));
   
String tableName = "Tools";  
Table table = dynamoDB.getTable(tableName); 
Index index = table.getIndex("LineIndex");  
QuerySpec spec = new QuerySpec() 
   .withKeyConditionExpression("Make = :v_make and Line = :v_line") 
   .withValueMap(new ValueMap() 
   .withString(":v_make", "Depault") 
   .withString(":v_line", "SuperSawz"));
      
ItemCollection<QueryOutcome> items = index.query(spec);
Iterator<Item> itemsIter = items.iterator();

while (itemsIter.hasNext()) { 
   Item item = itemsIter.next(); 
   System.out.println(item.toJSONPretty()); 
}

Aşağıdaki örneği de inceleyebilirsiniz.

Note- Aşağıdaki örnek, önceden oluşturulmuş bir veri kaynağını varsayabilir. Yürütme girişiminde bulunmadan önce, destekleyici kitaplıklar edinin ve gerekli veri kaynaklarını oluşturun (gerekli özelliklere sahip tablolar veya diğer başvurulan kaynaklar).

Aşağıdaki örnekte ayrıca Eclipse IDE, bir AWS kimlik bilgileri dosyası ve bir Eclipse AWS Java Projesi içindeki AWS Toolkit kullanılmaktadır.

Misal

import java.util.ArrayList;
import java.util.Iterator;

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;

import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Index;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.ItemCollection;
import com.amazonaws.services.dynamodbv2.document.PutItemOutcome;
import com.amazonaws.services.dynamodbv2.document.QueryOutcome;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.QuerySpec;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;

import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.LocalSecondaryIndex;
import com.amazonaws.services.dynamodbv2.model.Projection;
import com.amazonaws.services.dynamodbv2.model.ProjectionType;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.ReturnConsumedCapacity;
import com.amazonaws.services.dynamodbv2.model.Select;

public class LocalSecondaryIndexSample {  
   static DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient( 
      new ProfileCredentialsProvider()));  
   public static String tableName = "ProductOrders";  
   
   public static void main(String[] args) throws Exception {  
      createTable();
      query(null); 
      query("IsOpenIndex"); 
      query("OrderCreationDateIndex"); 
   }
   public static void createTable() { 
      CreateTableRequest createTableRequest = new CreateTableRequest() 
         .withTableName(tableName) 
         .withProvisionedThroughput(new ProvisionedThroughput() 
         .withReadCapacityUnits((long) 1) 
         .withWriteCapacityUnits((long) 1));
         
      // Table partition and sort keys attributes 
      ArrayList<AttributeDefinition> attributeDefinitions = new 
         ArrayList<AttributeDefinition>(); 
      
      attributeDefinitions.add(new AttributeDefinition() 
         .withAttributeName("CustomerID") 
         .withAttributeType("S"));
         
      attributeDefinitions.add(new AttributeDefinition() 
         .withAttributeName("OrderID") 
         .withAttributeType("N"));
         
      // Index primary key attributes 
      attributeDefinitions.add(new AttributeDefinition() 
         .withAttributeName("OrderDate") 
         .withAttributeType("N"));
         
      attributeDefinitions.add(new AttributeDefinition() 
         .withAttributeName("OpenStatus") 
         .withAttributeType("N"));  
      createTableRequest.setAttributeDefinitions(attributeDefinitions);
      
      // Table key schema 
      ArrayList<KeySchemaElement> tableKeySchema = new
         ArrayList<KeySchemaElement>(); 
      tableKeySchema.add(new KeySchemaElement()  
         .withAttributeName("CustomerID") 
         .withKeyType(KeyType.HASH));                    //Partition key
         
      tableKeySchema.add(new KeySchemaElement() 
         .withAttributeName("OrderID") 
         .withKeyType(KeyType.RANGE));                   //Sort key
         
      createTableRequest.setKeySchema(tableKeySchema);  
      ArrayList<LocalSecondaryIndex> localSecondaryIndexes = new 
         ArrayList<LocalSecondaryIndex>();  
      
      // OrderDateIndex 
      LocalSecondaryIndex orderDateIndex = new LocalSecondaryIndex() 
         .withIndexName("OrderDateIndex");
         
      // OrderDateIndex key schema 
      ArrayList<KeySchemaElement> indexKeySchema = new 
         ArrayList<KeySchemaElement>(); 
      indexKeySchema.add(new KeySchemaElement() 
         .withAttributeName("CustomerID") 
         .withKeyType(KeyType.HASH));                   //Partition key
         
      indexKeySchema.add(new KeySchemaElement() 
         .withAttributeName("OrderDate") 
         .withKeyType(KeyType.RANGE));                   //Sort key
      orderDateIndex.setKeySchema(indexKeySchema);
      
      // OrderCreationDateIndex projection w/attributes list 
      Projection projection = new Projection() 
         .withProjectionType(ProjectionType.INCLUDE); 
      
      ArrayList<String> nonKeyAttributes = new ArrayList<String>(); 
      nonKeyAttributes.add("ProdCat"); 
      nonKeyAttributes.add("ProdNomenclature"); 
      projection.setNonKeyAttributes(nonKeyAttributes);
      orderCreationDateIndex.setProjection(projection);  
      localSecondaryIndexes.add(orderDateIndex);  
      
      // IsOpenIndex 
      LocalSecondaryIndex isOpenIndex = new LocalSecondaryIndex() 
         .withIndexName("IsOpenIndex");  
      
      // OpenStatusIndex key schema 
      indexKeySchema = new ArrayList<KeySchemaElement>(); 
      indexKeySchema.add(new KeySchemaElement() 
         .withAttributeName("CustomerID") 
         .withKeyType(KeyType.HASH));                   //Partition key
         
      indexKeySchema.add(new KeySchemaElement() 
         .withAttributeName("OpenStatus") 
         .withKeyType(KeyType.RANGE));                   //Sort key
         
      // OpenStatusIndex projection 
      projection = new Projection() .withProjectionType(ProjectionType.ALL);  
      OpenStatusIndex.setKeySchema(indexKeySchema); 
      OpenStatusIndex.setProjection(projection);  
      localSecondaryIndexes.add(OpenStatusIndex);  
      
      // Put definitions in CreateTable request 
      createTableRequest.setLocalSecondaryIndexes(localSecondaryIndexes);  
      System.out.println("Spawning table " + tableName + "..."); 
      System.out.println(dynamoDB.createTable(createTableRequest));  
      
      // Pause for ACTIVE status 
      System.out.println("Waiting for ACTIVE table:" + tableName); 
      try { 
         Table table = dynamoDB.getTable(tableName);
         table.waitForActive(); 
      } catch (InterruptedException e) { 
         e.printStackTrace(); 
      } 
   }
   public static void query(String indexName) {  
      Table table = dynamoDB.getTable(tableName);  
      System.out.println("\n*************************************************\n"); 
      System.out.println("Executing query on" + tableName);  
      QuerySpec querySpec = new QuerySpec() 
         .withConsistentRead(true) 
         .withScanIndexForward(true) 
         .withReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL);
      
      if (indexName == "OpenStatusIndex") {  
         System.out.println("\nEmploying index: '" + indexName 
            + "' open orders for this customer.");
            
         System.out.println( 
            "Returns only user-specified attribute list\n"); 
         Index index = table.getIndex(indexName); 
             
         querySpec.withKeyConditionExpression("CustomerID = :v_custmid and 
            OpenStatus = :v_openstat") 
            .withValueMap(new ValueMap() 
            .withString(":v_custmid", "[email protected]") 
            .withNumber(":v_openstat", 1));  
         
         querySpec.withProjectionExpression( 
            "OrderDate, ProdCat, ProdNomenclature, OrderStatus"); 
            ItemCollection<QueryOutcome> items = index.query(querySpec); 
            Iterator<Item> iterator = items.iterator();  
            System.out.println("Printing query results...");  
            
         while (iterator.hasNext()) { 
            System.out.println(iterator.next().toJSONPretty()); 
         }  
      } else if (indexName == "OrderDateIndex") { 
         System.out.println("\nUsing index: '" + indexName 
            + "': this customer's orders placed after 05/22/2016."); 
         System.out.println("Projected attributes are returned\n"); 
         Index index = table.getIndex(indexName); 
             
         querySpec.withKeyConditionExpression("CustomerID = :v_custmid and OrderDate 
            >= :v_ordrdate") 
            .withValueMap(new ValueMap() 
            .withString(":v_custmid", "[email protected]") 
            .withNumber(":v_ordrdate", 20160522));
               
         querySpec.withSelect(Select.ALL_PROJECTED_ATTRIBUTES);  
         ItemCollection<QueryOutcome> items = index.query(querySpec); 
         Iterator<Item> iterator = items.iterator();  
         System.out.println("Printing query results...");  
            
         while (iterator.hasNext()) { 
            System.out.println(iterator.next().toJSONPretty()); 
         }  
      } else { 
         System.out.println("\nNo index: All Jane's orders by OrderID:\n"); 
         querySpec.withKeyConditionExpression("CustomerID = :v_custmid") 
            .withValueMap(new ValueMap()
            .withString(":v_custmid", "[email protected]"));  
         
         ItemCollection<QueryOutcome> items = table.query(querySpec); 
         Iterator<Item> iterator = items.iterator();  
         System.out.println("Printing query results...");  
         
         while (iterator.hasNext()) { 
            System.out.println(iterator.next().toJSONPretty()); 
         } 
      } 
   } 
}