DynamoDB - Chỉ mục phụ toàn cầu

Các ứng dụng yêu cầu nhiều loại truy vấn với các thuộc tính khác nhau có thể sử dụng một hoặc nhiều chỉ mục phụ toàn cầu để thực hiện các truy vấn chi tiết này.

For example - Hệ thống theo dõi người dùng, trạng thái đăng nhập và thời gian họ đăng nhập. Sự phát triển của ví dụ trước làm chậm các truy vấn trên dữ liệu của nó.

Các chỉ mục thứ cấp toàn cầu tăng tốc các truy vấn bằng cách tổ chức lựa chọn các thuộc tính từ một bảng. Chúng sử dụng các khóa chính để sắp xếp dữ liệu và không yêu cầu thuộc tính bảng khóa hoặc lược đồ khóa giống hệt với bảng.

Tất cả các chỉ mục phụ toàn cầu phải bao gồm khóa phân vùng, với tùy chọn là khóa sắp xếp. Lược đồ khóa chỉ mục có thể khác với bảng và các thuộc tính khóa chỉ mục có thể sử dụng bất kỳ thuộc tính chuỗi, số hoặc bảng nhị phân cấp cao nhất nào.

Trong một phép chiếu, bạn có thể sử dụng các thuộc tính bảng khác, tuy nhiên, các truy vấn không truy xuất từ ​​bảng mẹ.

Phép chiếu thuộc tính

Phép chiếu bao gồm một tập thuộc tính được sao chép từ bảng sang chỉ mục phụ. Phép chiếu luôn xảy ra với khóa phân vùng bảng và khóa sắp xếp. Trong các truy vấn, phép chiếu cho phép DynamoDB truy cập vào bất kỳ thuộc tính nào của phép chiếu; về cơ bản chúng tồn tại như một bảng riêng của chúng.

Trong tạo chỉ mục phụ, bạn phải chỉ định các thuộc tính cho phép chiếu. DynamoDB cung cấp ba cách để thực hiện tác vụ này:

  • KEYS_ONLY- Tất cả các mục chỉ mục bao gồm phân vùng bảng và sắp xếp các giá trị khóa, và các giá trị khóa chỉ mục. Điều này tạo ra chỉ số nhỏ nhất.

  • INCLUDE - Nó bao gồm các thuộc tính KEYS_ONLY và các thuộc tính không phải khóa được chỉ định.

  • ALL - Nó bao gồm tất cả các thuộc tính bảng nguồn, tạo chỉ mục lớn nhất có thể.

Lưu ý sự cân bằng trong việc chiếu các thuộc tính vào một chỉ số thứ cấp toàn cầu, liên quan đến thông lượng và chi phí lưu trữ.

Hãy xem xét các điểm sau:

  • Nếu bạn chỉ cần truy cập vào một vài thuộc tính, với độ trễ thấp, hãy chỉ chiếu những thuộc tính bạn cần. Điều này làm giảm chi phí lưu trữ và ghi.

  • Nếu một ứng dụng thường xuyên truy cập vào các thuộc tính không phải khóa nhất định, hãy chiếu chúng vì chi phí lưu trữ thấp hơn so với mức tiêu thụ quét.

  • Bạn có thể chiếu các tập hợp lớn các thuộc tính được truy cập thường xuyên, tuy nhiên, điều này mang lại chi phí lưu trữ cao.

  • Sử dụng KEYS_ONLY cho các truy vấn bảng không thường xuyên và ghi / cập nhật thường xuyên. Điều này kiểm soát kích thước, nhưng vẫn cung cấp hiệu suất tốt trên các truy vấn.

Truy vấn và quét chỉ mục thứ cấp toàn cầu

Bạn có thể sử dụng các truy vấn để truy cập một hoặc nhiều mục trong một chỉ mục. Bạn phải chỉ định chỉ mục và tên bảng, các thuộc tính và điều kiện mong muốn; với tùy chọn trả về kết quả theo thứ tự tăng dần hoặc giảm dần.

Bạn cũng có thể sử dụng quét để lấy tất cả dữ liệu chỉ mục. Nó yêu cầu tên bảng và chỉ mục. Bạn sử dụng biểu thức bộ lọc để truy xuất dữ liệu cụ thể.

Đồng bộ hóa dữ liệu bảng và chỉ mục

DynamoDB tự động thực hiện đồng bộ hóa trên các chỉ mục với bảng mẹ của chúng. Mỗi thao tác sửa đổi trên các mục gây ra cập nhật không đồng bộ, tuy nhiên, các ứng dụng không ghi trực tiếp vào chỉ mục.

Bạn cần hiểu tác động của việc bảo trì DynamoDB đối với các chỉ số. Khi tạo chỉ mục, bạn chỉ định các thuộc tính và kiểu dữ liệu chính, có nghĩa là khi ghi, các kiểu dữ liệu đó phải khớp với kiểu dữ liệu lược đồ chính.

Tuy nhiên, khi tạo hoặc xóa mục, các chỉ mục cập nhật theo cách nhất quán cuối cùng, các cập nhật đối với dữ liệu được truyền tải trong một phần của giây (trừ khi xảy ra lỗi hệ thống thuộc một số loại). Bạn phải giải trình cho sự chậm trễ này trong các ứng dụng.

Throughput Considerations in Global Secondary Indexes- Nhiều chỉ số thứ cấp toàn cầu tác động đến thông lượng. Việc tạo chỉ mục yêu cầu các thông số kỹ thuật của đơn vị dung lượng, tồn tại tách biệt với bảng, dẫn đến các hoạt động sử dụng đơn vị dung lượng chỉ mục hơn là đơn vị bảng.

Điều này có thể dẫn đến điều chỉnh nếu truy vấn hoặc ghi vượt quá thông lượng được cấp phép. Xem cài đặt thông lượng bằng cách sử dụngDescribeTable.

Read Capacity- Các chỉ mục thứ cấp toàn cầu cung cấp tính nhất quán cuối cùng. Trong các truy vấn, DynamoDB thực hiện các tính toán cung cấp giống hệt như được sử dụng cho các bảng, với sự khác biệt duy nhất là sử dụng kích thước mục nhập chỉ mục thay vì kích thước mục. Giới hạn của một truy vấn trả về vẫn là 1MB, bao gồm kích thước tên thuộc tính và các giá trị trên mọi mặt hàng được trả về.

Ghi dung lượng

Khi hoạt động ghi xảy ra, chỉ mục bị ảnh hưởng sẽ sử dụng các đơn vị ghi. Chi phí thông lượng ghi là tổng đơn vị khả năng ghi được tiêu thụ trong quá trình ghi bảng và đơn vị tiêu thụ trong các bản cập nhật chỉ mục. Một thao tác ghi thành công cần có đủ dung lượng, nếu không sẽ dẫn đến việc điều chỉnh.

Chi phí ghi cũng phụ thuộc vào các yếu tố nhất định, một số yếu tố như sau:

  • Các mục mới xác định thuộc tính được lập chỉ mục hoặc cập nhật mặt hàng xác định các thuộc tính được lập chỉ mục chưa xác định sử dụng một thao tác ghi duy nhất để thêm mặt hàng vào chỉ mục.

  • Các bản cập nhật thay đổi giá trị thuộc tính khóa được lập chỉ mục sử dụng hai lần ghi để xóa một mục và ghi một mục mới.

  • Việc kích hoạt ghi bảng để xóa một thuộc tính được lập chỉ mục sử dụng một lần ghi duy nhất để xóa phép chiếu mục cũ trong chỉ mục.

  • Các mục vắng mặt trong chỉ mục trước và sau khi thao tác cập nhật không được ghi.

  • Các bản cập nhật chỉ thay đổi giá trị thuộc tính dự kiến ​​trong lược đồ khóa chỉ mục và không thay đổi giá trị thuộc tính khóa được lập chỉ mục, sử dụng một lần ghi để cập nhật giá trị của các thuộc tính dự kiến ​​vào chỉ mục.

Tất cả các yếu tố này giả định kích thước mặt hàng nhỏ hơn hoặc bằng 1KB.

Lưu trữ chỉ mục thứ cấp toàn cầu

Khi ghi một mục, DynamoDB tự động sao chép tập hợp các thuộc tính phù hợp vào bất kỳ chỉ số nào mà các thuộc tính phải tồn tại. Điều này ảnh hưởng đến tài khoản của bạn bằng cách tính phí nó cho việc lưu trữ vật phẩm trong bảng và lưu trữ thuộc tính. Không gian được sử dụng là kết quả từ tổng các đại lượng này -

  • Kích thước byte của khóa chính của bảng
  • Kích thước byte của thuộc tính khóa chỉ mục
  • Kích thước byte của các thuộc tính dự kiến
  • Chi phí 100 byte cho mỗi mục chỉ mục

Bạn có thể ước tính nhu cầu lưu trữ thông qua ước tính kích thước mục trung bình và nhân với số lượng mục trong bảng có thuộc tính khóa chỉ mục phụ toàn cầu.

DynamoDB không ghi dữ liệu mục cho mục bảng có thuộc tính không xác định được định nghĩa là phân vùng chỉ mục hoặc khóa sắp xếp.

Chỉ số thứ cấp toàn cầu thô

Tạo một bảng với các chỉ mục phụ chung bằng cách sử dụng CreateTable hoạt động được ghép nối với GlobalSecondaryIndexestham số. Bạn phải chỉ định một thuộc tính để dùng làm khóa phân vùng chỉ mục hoặc sử dụng một thuộc tính khác cho khóa sắp xếp chỉ mục. Tất cả các thuộc tính khóa chỉ mục phải là chuỗi, số hoặc vô hướng nhị phân. Bạn cũng phải cung cấp cài đặt thông lượng, bao gồmReadCapacityUnitsWriteCapacityUnits.

Sử dụng UpdateTable để thêm các chỉ mục phụ toàn cầu vào các bảng hiện có bằng cách sử dụng tham số GlobalSecondaryIndexes một lần nữa.

Trong thao tác này, bạn phải cung cấp các đầu vào sau:

  • Tên chỉ mục
  • Lược đồ chính
  • Thuộc tính dự kiến
  • Cài đặt thông lượng

Bằng cách thêm chỉ mục phụ toàn cầu, có thể mất một khoảng thời gian đáng kể với các bảng lớn do khối lượng mục, khối lượng thuộc tính dự kiến, khả năng ghi và hoạt động ghi. Sử dụngCloudWatch số liệu để giám sát quá trình.

Sử dụng DescribeTableđể tìm nạp thông tin trạng thái cho chỉ mục phụ toàn cầu. Nó trả về một trong bốnIndexStatus cho GlobalSecondaryIndexes -

  • CREATING - Nó chỉ ra giai đoạn xây dựng của chỉ mục và tính khả dụng của nó.

  • ACTIVE - Nó cho biết mức độ sẵn sàng của chỉ số để sử dụng.

  • UPDATING - Nó cho biết trạng thái cập nhật của cài đặt thông lượng.

  • DELETING - Nó cho biết trạng thái xóa của chỉ mục và vĩnh viễn không có sẵn để sử dụng.

Cập nhật cài đặt thông lượng được cung cấp chỉ mục thứ cấp toàn cầu trong giai đoạn tải / lấp đầy (ghi các thuộc tính DynamoDB vào chỉ mục và theo dõi các mục được thêm / xóa / cập nhật). Sử dụngUpdateTable để thực hiện thao tác này.

Bạn nên nhớ rằng bạn không thể thêm / xóa các chỉ số khác trong giai đoạn lấp đầy.

Sử dụng UpdateTable để xóa các chỉ mục phụ toàn cầu. Nó chỉ cho phép xóa một chỉ mục cho mỗi hoạt động, tuy nhiên, bạn có thể chạy nhiều hoạt động đồng thời, tối đa năm. Quá trình xóa không ảnh hưởng đến hoạt động đọc / ghi của bảng mẹ, nhưng bạn không thể thêm / xóa các chỉ số khác cho đến khi thao tác hoàn tất.

Sử dụng Java để làm việc với các chỉ mục thứ cấp toàn cầu

Tạo một bảng với một chỉ mục thông qua CreateTable. Chỉ cần tạo một phiên bản lớp DynamoDB,CreateTableRequest cá thể lớp cho thông tin yêu cầu và chuyển đối tượng yêu cầu đến phương thức CreateTable.

Chương trình sau đây là một ví dụ ngắn gọn:

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient ( 
   new ProfileCredentialsProvider()));
   
// Attributes 
ArrayList<AttributeDefinition> attributeDefinitions = new 
   ArrayList<AttributeDefinition>();  
attributeDefinitions.add(new AttributeDefinition() 
   .withAttributeName("City") 
   .withAttributeType("S"));
   
attributeDefinitions.add(new AttributeDefinition() 
   .withAttributeName("Date") 
   .withAttributeType("S"));
   
attributeDefinitions.add(new AttributeDefinition() 
   .withAttributeName("Wind") 
   .withAttributeType("N"));
   
// Key schema of the table 
ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<KeySchemaElement>(); 
tableKeySchema.add(new KeySchemaElement()
   .withAttributeName("City") 
   .withKeyType(KeyType.HASH));              //Partition key
   
tableKeySchema.add(new KeySchemaElement() 
   .withAttributeName("Date") 
   .withKeyType(KeyType.RANGE));             //Sort key
   
// Wind index 
GlobalSecondaryIndex windIndex = new GlobalSecondaryIndex() 
   .withIndexName("WindIndex") 
   .withProvisionedThroughput(new ProvisionedThroughput() 
   .withReadCapacityUnits((long) 10) 
   .withWriteCapacityUnits((long) 1)) 
   .withProjection(new Projection().withProjectionType(ProjectionType.ALL));
   
ArrayList<KeySchemaElement> indexKeySchema = new ArrayList<KeySchemaElement>(); 
indexKeySchema.add(new KeySchemaElement() 
   .withAttributeName("Date") 
   .withKeyType(KeyType.HASH));              //Partition key
   
indexKeySchema.add(new KeySchemaElement() 
   .withAttributeName("Wind") 
   .withKeyType(KeyType.RANGE));             //Sort key
   
windIndex.setKeySchema(indexKeySchema);  
CreateTableRequest createTableRequest = new CreateTableRequest() 
   .withTableName("ClimateInfo") 
   .withProvisionedThroughput(new ProvisionedThroughput() 
   .withReadCapacityUnits((long) 5) 
   .withWriteCapacityUnits((long) 1))
   .withAttributeDefinitions(attributeDefinitions) 
   .withKeySchema(tableKeySchema) 
   .withGlobalSecondaryIndexes(windIndex); 
Table table = dynamoDB.createTable(createTableRequest); 
System.out.println(table.getDescription());

Truy xuất thông tin chỉ mục với DescribeTable. Đầu tiên, tạo một cá thể lớp DynamoDB. Sau đó, tạo một cá thể lớp Bảng để nhắm mục tiêu một chỉ mục. Cuối cùng, chuyển bảng đến phương thức mô tả.

Đây là một ví dụ ngắn -

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient ( 
   new ProfileCredentialsProvider()));
   
Table table = dynamoDB.getTable("ClimateInfo"); 
TableDescription tableDesc = table.describe();  
Iterator<GlobalSecondaryIndexDescription> gsiIter = 
   tableDesc.getGlobalSecondaryIndexes().iterator(); 

while (gsiIter.hasNext()) { 
   GlobalSecondaryIndexDescription gsiDesc = gsiIter.next(); 
   System.out.println("Index data " + gsiDesc.getIndexName() + ":");  
   Iterator<KeySchemaElement> kse7Iter = gsiDesc.getKeySchema().iterator(); 
   
   while (kseIter.hasNext()) { 
      KeySchemaElement kse = kseIter.next(); 
      System.out.printf("\t%s: %s\n", kse.getAttributeName(), kse.getKeyType()); 
   }
   Projection projection = gsiDesc.getProjection(); 
   System.out.println("\tProjection type: " + projection.getProjectionType()); 
   
   if (projection.getProjectionType().toString().equals("INCLUDE")) { 
      System.out.println("\t\tNon-key projected attributes: " 
         + projection.getNonKeyAttributes()); 
   } 
}

Sử dụng Truy vấn để thực hiện truy vấn chỉ mục như với truy vấn bảng. Chỉ cần tạo một cá thể lớp DynamoDB, một cá thể lớp Bảng cho chỉ mục đích, một cá thể lớp Chỉ mục cho chỉ mục cụ thể và chuyển chỉ mục và đối tượng truy vấn cho phương thức truy vấn.

Hãy xem đoạn mã sau để hiểu rõ hơn -

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient ( 
   new ProfileCredentialsProvider()));
   
Table table = dynamoDB.getTable("ClimateInfo"); 
Index index = table.getIndex("WindIndex");  
QuerySpec spec = new QuerySpec() 
   .withKeyConditionExpression("#d = :v_date and Wind = :v_wind") 
   .withNameMap(new NameMap() 
   .with("#d", "Date"))
   .withValueMap(new ValueMap() 
   .withString(":v_date","2016-05-15") 
   .withNumber(":v_wind",0));
   
ItemCollection<QueryOutcome> items = index.query(spec);
Iterator<Item> iter = items.iterator();

while (iter.hasNext()) {
   System.out.println(iter.next().toJSONPretty()); 
}

Chương trình sau đây là một ví dụ lớn hơn để hiểu rõ hơn -

Note- Chương trình sau có thể giả sử một nguồn dữ liệu đã tạo trước đó. Trước khi cố gắng thực thi, hãy thu thập các thư viện hỗ trợ và tạo các nguồn dữ liệu cần thiết (các bảng có các đặc điểm bắt buộc hoặc các nguồn tham chiếu khác).

Ví dụ này cũng sử dụng Eclipse IDE, tệp thông tin đăng nhập AWS và Bộ công cụ AWS trong Dự án Java AWS của Eclipse.

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.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.GlobalSecondaryIndex;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.Projection;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;

public class GlobalSecondaryIndexSample {  
   static DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient ( 
      new ProfileCredentialsProvider()));  
   public static String tableName = "Bugs";   
   public static void main(String[] args) throws Exception {  
      createTable(); 
      queryIndex("CreationDateIndex"); 
      queryIndex("NameIndex"); 
      queryIndex("DueDateIndex"); 
   }
   public static void createTable() {  
      // Attributes 
      ArrayList<AttributeDefinition> attributeDefinitions = new 
         ArrayList<AttributeDefinition>();  
      attributeDefinitions.add(new AttributeDefinition()
         .withAttributeName("BugID") 
         .withAttributeType("S")); 
         
      attributeDefinitions.add(new AttributeDefinition() 
         .withAttributeName("Name")
         .withAttributeType("S"));
         
      attributeDefinitions.add(new AttributeDefinition() 
         .withAttributeName("CreationDate")
         .withAttributeType("S"));
         
      attributeDefinitions.add(new AttributeDefinition() 
         .withAttributeName("DueDate") 
         .withAttributeType("S"));
         
      // Table Key schema
      ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<KeySchemaElement>(); 
      tableKeySchema.add (new KeySchemaElement() 
         .withAttributeName("BugID") 
         .withKeyType(KeyType.HASH));              //Partition key 
      
      tableKeySchema.add (new KeySchemaElement() 
         .withAttributeName("Name") 
         .withKeyType(KeyType.RANGE));             //Sort key
         
      // Indexes' initial provisioned throughput
      ProvisionedThroughput ptIndex = new ProvisionedThroughput()
         .withReadCapacityUnits(1L)
         .withWriteCapacityUnits(1L);
         
      // CreationDateIndex 
      GlobalSecondaryIndex creationDateIndex = new GlobalSecondaryIndex() 
         .withIndexName("CreationDateIndex") 
         .withProvisionedThroughput(ptIndex) 
         .withKeySchema(new KeySchemaElement() 
         .withAttributeName("CreationDate") 
         .withKeyType(KeyType.HASH),               //Partition key 
         new KeySchemaElement()
         .withAttributeName("BugID") 
         .withKeyType(KeyType.RANGE))              //Sort key 
         .withProjection(new Projection() 
         .withProjectionType("INCLUDE") 
         .withNonKeyAttributes("Description", "Status"));
         
      // NameIndex 
      GlobalSecondaryIndex nameIndex = new GlobalSecondaryIndex() 
         .withIndexName("NameIndex") 
         .withProvisionedThroughput(ptIndex) 
         .withKeySchema(new KeySchemaElement()  
         .withAttributeName("Name")  
         .withKeyType(KeyType.HASH),                  //Partition key 
         new KeySchemaElement()  
         .withAttributeName("BugID")  
         .withKeyType(KeyType.RANGE))                 //Sort key 
         .withProjection(new Projection() 
         .withProjectionType("KEYS_ONLY"));
         
      // DueDateIndex 
      GlobalSecondaryIndex dueDateIndex = new GlobalSecondaryIndex() 
         .withIndexName("DueDateIndex") 
         .withProvisionedThroughput(ptIndex) 
         .withKeySchema(new KeySchemaElement() 
         .withAttributeName("DueDate") 
         .withKeyType(KeyType.HASH))               //Partition key 
         .withProjection(new Projection() 
         .withProjectionType("ALL"));
         
      CreateTableRequest createTableRequest = new CreateTableRequest() 
         .withTableName(tableName) 
         .withProvisionedThroughput( new ProvisionedThroughput() 
         .withReadCapacityUnits( (long) 1) 
         .withWriteCapacityUnits( (long) 1)) 
         .withAttributeDefinitions(attributeDefinitions)
         .withKeySchema(tableKeySchema)
         .withGlobalSecondaryIndexes(creationDateIndex, nameIndex, dueDateIndex);  
         System.out.println("Creating " + tableName + "..."); 
         dynamoDB.createTable(createTableRequest);  
      
      // Pause for active table state 
      System.out.println("Waiting for ACTIVE state of " + tableName); 
      try { 
         Table table = dynamoDB.getTable(tableName); 
         table.waitForActive(); 
      } catch (InterruptedException e) { 
         e.printStackTrace(); 
      } 
   }
   public static void queryIndex(String indexName) { 
      Table table = dynamoDB.getTable(tableName);  
      System.out.println 
      ("\n*****************************************************\n"); 
      System.out.print("Querying index " + indexName + "...");  
      Index index = table.getIndex(indexName);  
      ItemCollection<QueryOutcome> items = null; 
      QuerySpec querySpec = new QuerySpec();  
      
      if (indexName == "CreationDateIndex") { 
         System.out.println("Issues filed on 2016-05-22"); 
         querySpec.withKeyConditionExpression("CreationDate = :v_date and begins_with
            (BugID, :v_bug)") 
            .withValueMap(new ValueMap() 
            .withString(":v_date","2016-05-22")
            .withString(":v_bug","A-")); 
         items = index.query(querySpec); 
      } else if (indexName == "NameIndex") { 
         System.out.println("Compile error"); 
         querySpec.withKeyConditionExpression("Name = :v_name and begins_with
            (BugID, :v_bug)") 
            .withValueMap(new ValueMap() 
            .withString(":v_name","Compile error") 
            .withString(":v_bug","A-")); 
         items = index.query(querySpec); 
      } else if (indexName == "DueDateIndex") { 
         System.out.println("Items due on 2016-10-15"); 
         querySpec.withKeyConditionExpression("DueDate = :v_date") 
         .withValueMap(new ValueMap() 
         .withString(":v_date","2016-10-15")); 
         items = index.query(querySpec); 
      } else { 
         System.out.println("\nInvalid index name"); 
         return; 
      }  
      Iterator<Item> iterator = items.iterator(); 
      System.out.println("Query: getting result..."); 
      
      while (iterator.hasNext()) { 
         System.out.println(iterator.next().toJSONPretty()); 
      } 
   } 
}