КатегорииElasticsearch

Elasticsearch — Урок 3.8 Отношения между документами

В реляционном мире данные часто делятся на несколько таблиц и связаны с использованием внешних ключей. Но в мире NoSQL данные обычно денормализуются и хранятся как один большой документ. Однако часто бывает целесообразно все же разделить эти данные. Данные в Elasticsearch неизменяемы. Обновление существующего документа означает получение старого документа, изменение и повторную индексацию его в качестве нового документа. Обновление — дорогостоящая операция. Нужно стремиться свести обновления до минимума.

Например, статья в блоге может содержать один или несколько комментариев, а заказ может иметь одну или несколько позиций. Если мы можем разделить статью и комментарии, нам не нужно обновлять статью при появлении нового комментария. Elasticsearch предоставляет два способа обработки отношений между документами. Первый — родитель-ребенок, а второй — вложенный. Оба имеют свои плюсы и минусы. Во-первых, давайте обсудим отношение родитель-ребенок.

Отношение родитель-ребенок

Для отношений между родительскими и дочерними документами связь устанавливается путем указания родительского идентификатора при создании дочерних документов. Оба типа документов индексируются, как и любые другие документы, но при индексировании дочернего документа требуется родительский идентификатор. По сути это отношение «один ко многим». Родительский документ может иметь несколько дочерних документов, но дочерний документ может иметь только один родительский документ.

Следует рассмотреть возможность использования отношений родитель-ребенок в следующих случаях:

  • Независимое обновление обоих типов документов. Например, новый комментарий может быть добавлен без обновления статьи
  • Документы потомки обновляются чаще, чем исходные документы

Давайте установим маппинг для индекса blog, у вас есть тип article, который является родительским, и тип comment, который является дочерним. Отображение parent-child между статьей и комментарием можно установить так:

PUT blog
 {
   "mappings": {
     "article": { #Родитель
       "properties": {
         "title": {
           "type": "text"
         },
         "category": {
           "type": "keyword"
         }
       }
     },
     "comment": { #Ребенок
       "_parent": {
         "type": "article"
       },
       "properties": {
         "comment": {
           "type": "text"
         },
         "userid": {
           "type": "keyword"
         }
       }
     }
   }
 }

Теперь можно добавлять статьи, так и комментарии к ним:

#Родитель
PUT blog/article/1 
{
  "title" : "Привет МеДвед!!!",
  "category" : "Сумбур да каламбур"
}

#Ребенок
PUT blog/comment/10?parent=1
{
  "comment" : "Продаю силиконовые сиськи",
  "userid" : "user1"
}

Документ статьи (родительский) индексируется как обычный документ, а при индексировании документа комментария (дочерний элемент) указывается идентификатор статьи (родителя).

Elasticsearch предоставляет has_childhas_parentдля поддержки запроса parent-child. Например, мы можем запросить все статьи, содержащие комментарии от конкретного пользователя, как показано ниже:

 POST blog/article/_search
 {
   "query": {
     "has_child": {
       "type": "comment",
       "query": {
         "term": {
           "userid": "user1"
         }
       }
     }
   }
 }

Не беспокойтесь, если предыдущий запрос пока вам не сильно понятен. Мы обсудим запросы родитель-потомок  более подробно в 7 уроке. Хотя отношение родительского и дочернего документов кажется очень многообещающим, запросы очень дороги, поскольку Elasticsearch должен поддерживать сопоставление между родительскими и дочерними документами в памяти.

Как хранятся документы родитель-ребенка?

Документ потомок хранится в том же осколке, что и родительский документ. Сохраняя оба документа на одном осколке, Elasticsearch может избежать дополнительных издержек на извлечение данных. При индексировании дочернего документа он использует родительский идентификатор, чтобы найти осколок, где находиться родительский документ.

Nested (Вложенные)

Мы уже разбирали, как установить маппинг для вложенных документов в разделе про вложенные типы данных. Главным недостатком является то, что для обновления родительского или вложенного документа весь документ необходимо обновить. Например, у нас есть документ:

{
 "id": 1,
 "name": "User1",
 "address": [ #Nested
    {
      "street": "123 High Lane",
      "city": "Big City"
    },
    {
      "street" : "436 Low Lane",
      "city": "Small City"
    }
 ]
}

Чтобы обновить родительские поля документа, например, nameили обновить вложенные поля документа, как streetи весь пользовательский документ, необходимо обновить. Вложенные документы, такие как адрес, не могут быть доступны независимо, поскольку они скрыты.

Из за способа хранения, запросы на вложенные документы намного быстрее по сравнению с родительским-дочерним. Но если вам нужно обновлять дочерние документы чаще, чем родительский документ или наоборот, поскольку родительские / дочерние документы могут быть обновлены независимо, вариант родитель-ребенок может лучше подходойти в зависимости от потребностей приложения.

Elasticsearch поддерживает запросы вложенных документов с помощью вложенных запросов. Мы будем говорить о вложенных запросах в 7 уроке .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *