Skip to content

Count on secondary index causes missed key schema element  #27

@peoplemerge

Description

@peoplemerge

I have a time series table UserActivity

case class UserActivity(
  id: Long,
  activity: String,
  occurred: Long = System.currentTimeMillis()
)
object UserActivity {
  val tableName = "UserActivityV2"
  object Attributes {
    val id = "Id"
    val activity = "Activity"
    val occurred = "Occurred"
  }
  val tableRequest =
    new CreateTableRequest()
      .withTableName(UserActivity.tableName)
      .withProvisionedThroughput(
        Schema.provisionedThroughput(10L, 5L))
      .withAttributeDefinitions(
        Schema.numberAttribute(Attributes.id),
        Schema.numberAttribute(Attributes.occurred),
        Schema.stringAttribute(Attributes.activity)
      )
      .withKeySchema(
        Schema.hashKey(Attributes.id),
        Schema.rangeKey(Attributes.occurred))
      .withGlobalSecondaryIndexes(
        new GlobalSecondaryIndex()
          .withIndexName("ActivitiesOccurred")
          .withKeySchema(
            Schema.hashKey(Attributes.activity),
            Schema.rangeKey(Attributes.occurred))
          .withProjection(new Projection().withProjectionType(ProjectionType.KEYS_ONLY))
          .withProvisionedThroughput(
            Schema.provisionedThroughput(10L, 5L)),

Using the AWS UI, I can query the index. Although I didn't find an example for running a query, I came up with:

mapper.countQuery[UserActivity](
      mapper.CountQueryMagnet.countQuerySecondaryIndex(
        "ActivitiesOccurred",
        "sometext",
        "Occurred",
        QueryCondition.greaterThan(1421023065979l)
      ))

However this blows up with:

com.amazonaws.AmazonServiceException: Query condition missed key schema element Activity (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: KD4364FBV747MPFBQALD9ONS17VV4KQNSO5AEMVJF66Q9ASUAAJG)
    at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:1077)
    at com.amazonaws.http.AmazonHttpClient.executeOneRequest(AmazonHttpClient.java:725)
    at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:460)
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:295)
    at com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient.invoke(AmazonDynamoDBClient.java:3106)
    at com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient.query(AmazonDynamoDBClient.java:1118)
    at com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsyncClient$18.call(AmazonDynamoDBAsyncClient.java:1557)
    at com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsyncClient$18.call(AmazonDynamoDBAsyncClient.java:1553)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

Is this due to a feature that needs to be implemented upstream? See: aws-amplify/aws-sdk-ios#75

My build.sbt has:

  "com.amazonaws" % "aws-java-sdk" % "1.9.14"

that's latest, at least as of last week.

UPDATE: Here is the serializer


  implicit object userActivitySerializer
    extends DynamoDBSerializer[UserActivity] {

    override val tableName = UserActivity.tableName
    override val hashAttributeName = Attributes.id
    override val rangeAttributeName = Some[String](Attributes.occurred)

    override def primaryKeyOf(userActivity: UserActivity) =
      Map(Attributes.id -> userActivity.id,
        Attributes.occurred -> userActivity.occurred
      )

    override def toAttributeMap(userActivity: UserActivity) =
      Map(
        Attributes.id     -> userActivity.id,
        Attributes.email -> userActivity.email,
        Attributes.activity  -> userActivity.activity,
        Attributes.occurred -> userActivity.occurred
      )

    override def fromAttributeMap(
      item: collection.mutable.Map[String, AttributeValue]) =
      UserActivity(
        id     = item(Attributes.id),
        email = item(Attributes.email),
        activity  = item(Attributes.activity),
        occurred = item(Attributes.occurred)
      )
  }

Hmm, looks like there may be a way to identify keys there. That could be my problem.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions