Как запросить карту списка смежности n:n в DynamoDB без использования сканирования

Я пытаюсь смоделировать систему каталогизации в DynamodDB. Он имеет «Каталоги», которые содержат «Коллекции». Каждая «Коллекция» может быть помечена многими «Тегами».

В СУБД я бы создал таблицу «Каталоги» с отношением 1: n к «Коллекциям». «Коллекции» будут иметь n:n с «Тегами», поскольку Коллекция может иметь несколько Тегов, а Тег может принадлежать нескольким Коллекциям.

Запросы, которые я хочу запустить:

1) Получить все каталоги

2) Получить каталог по ID

3) Получить коллекции по идентификатору каталога

Я читал на AWS, что могу использовать дизайн карты списка смежности (потому что у меня есть n: n с «Тегами»). Итак, вот структура моей таблицы:

PK         SK         name    
cat-1      cat-1      Sales Catalog
cat-1      col-1      Sales First Collection
cat-1      col-2      Sales Second Collection
cat-2      cat-2      Finance Catalog 
tag-1      tag-1      Recently Added Tag
col-1      tag-1      (collection, tag relationship)

Проблема здесь в том, что я должен использовать сканирование, которое, как я понимаю, неэффективно, чтобы получить все «Каталоги», потому что PK запроса должен быть «=», а не «Начинается с».

Единственное, что я могу придумать, это создать еще один атрибут, например «GSI_PK», и добавить «Catalog_1», когда PK — это cat-1, а SK — cat-1, «Catalog_2», когда PK — это cat-2, а SK — это cat-. 2. Я никогда не видел, чтобы это было сделано, поэтому я не уверен, что это правильный путь, и требуется некоторое обслуживание, если я когда-либо захочу изменить идентификаторы.

Есть идеи, как мне это сделать?


person Eitan    schedule 04.09.2018    source источник


Ответы (2)


В этом случае вы можете использовать PK как тип объекта, а SK как uuid. Запись будет выглядеть так { PK: "Catalog", SK: "uuid", ...other catalog fields }. Затем вы можете получить все каталоги, выполнив запрос в PK = Catalog.

Чтобы сохранить ассоциации, вы можете иметь GSI в двух полях sourcePK и relatedPK, где вы можете хранить записи, которые связывают вещи. Чтобы связать объект, вы должны создать запись, например, например. { PK: "Association", SK: "uuid", sourcePK: "category-1", relatedPK: "collection-1", ... other data on the association }. Чтобы найти объекты, связанные с «Каталогом» с идентификатором 1, вы должны выполнить запрос в GSI, где sourcePK = catalog-1.

С этой настройкой вам нужно быть осторожным с горячими клавишами и следить за тем, чтобы у вас никогда не было более 10 ГБ данных под одним и тем же ключом раздела в таблице или индексе.

person mparis    schedule 07.09.2018
comment
Хорошо, я думал в том же духе, добавляя столбец типа и создавая GSI для этого столбца. - person Eitan; 11.09.2018

Давайте пройдемся по нему. Я буду использовать GraphQL SDL для компоновки дизайна модели данных и запросов, но вы можете просто применить те же концепции напрямую к DynamoDB.

Сначала обдумывая модель данных, у нас будет что-то вроде:

type Catalog {
  id: ID!
  name: String

  # Use a DynamoDB query on the **Collection** table 
  # where the **catalogId = $ctx.source.id**. Use a GSI or make catalogId the PK.
  collections: [Collection]
}
type Collection {
  id: ID!
  name: String

  # Use a DynamoDB query on the **CollectionTag** table where
  # the **collectionId = $ctx.source.id**. Use a GSI or make the collectionId the PK.
  tags: [CollectionTag]
}
# The "association map" idea as a GraphQL type. The underlying table has a collectionId and tagId.
# Create objects of this type to associate a collection and tag in the many to many relationship.
type CollectionTag {
  # Do a GetItem on the **Collection** table where **id = $ctx.source.collectionId**
  collection: Collection

  # Do a GetItem on the **Tag** table where **id = $ctx.source.tagId**
  tag: Tag
}
type Tag {
  id: ID!
  name: String

  # Use a DynamoDB query on teh **CollectionTag** table where
  # the **tagId = $ctx.source.id**. If collectionId is the PK then make a GSI where this tagId is the PK.
  collections: [CollectionTag]
}

# Root level queries
type Query {
  # GetItem to **Catalog** table where **id = $ctx.args.id**
  getCatalog(id: ID!): Catalog

  # Scan to **Catalog** table. As long as you don't care about ordering on a filed in particular then
  # this will likely be okay at the top level. If you only want all catalogs where "arePublished = 1",
  # for example then we would likely change this.
  allCatalogs: [Catalog]

  # Note: You don't really need a getCollectionsByCatalogId(catalogId: ID!) at the top level because you can
  # use `query { getCatalog(id: "***") { collections { ... } } }` which is effectively the same thing.
  # You could add another field here if having it at the top level was a requirement
  getCollectionsByCatalogId(catalogId: ID!): [Collection]
}

Примечание. Везде, где я использую [Collection] или [Catalog] и т. д. выше, вы должны использовать тип оболочки CollectionConnection, CatalogConnection и т. д., чтобы включить разбиение на страницы.

person mparis    schedule 07.09.2018
comment
Поэтому мне нужна таблица отношений n:n, в которой все элементы хранятся в одной таблице. docs.aws.amazon.com/amazondynamodb/latest/ руководство разработчика/. В корневом запросе у вас есть все каталоги, и вы упоминаете сканирование, которое я сейчас делаю, но я понимаю, что сканирование неэффективно в Dynamo db, и было бы лучше использовать запрос - person Eitan; 07.09.2018
comment
Итак, в основном, как я могу получить все каталоги, запросив хеш-ключ в dynamodb в таблице смежности n: n сопоставленной таблице - person Eitan; 07.09.2018
comment
Ответил в новом ответе - person mparis; 07.09.2018