<type>В этой документации объясняется использование и конфигурацию «Esindex», который является вторичным индексом на основе Elasticsearch для Cassandra.
Этот плагин требует уже настроенного кластера Elasticsearch (ES).
Плагин будет установлен в обычном релизе Cassandra 4.0.x, загруженного с http://cassandra.apache.org/. В файлах конфигурации Cassandra нечего изменить для поддержки индекса. Поведение Кассандры остается неизменным для приложений, которые не используют индекс.
После создания в таблице Cassandra этот индекс позволяет выполнять запросы Elasticsearch «Полный текст» на Cassandra, используя CQL и возвращают соответствующие ряды из данных Cassandra. Использование этого плагина не требует изменения исходного кода Cassandra, мы внедрили индекс Elasticsearch для Cassandra, используя:

Протестированные версии являются Elasticsearch 5.x, 6.x, 7.x и Cassandra 4.0.x. Однако плагин также может работать с различными версиями Elasticsearch (1.7, 2.x 5.x, 6.x, 7.x), если приложение предоставляет соответствующие сопоставления и параметры. Другие версии Apache Cassandra, такие как 1.x 2.x, 3.x или 4.1 не поддерживаются, поскольку интерфейс вторичного индекса, используемый плагином, отличается. Другие поставщики Cassandra не испытываются, Scylladb не поддерживается.
| Версии | Elasticsearch 1.x | Elasticsearch 2.x | Elasticsearch 5.x | Elasticsearch 6.x | Elasticsearch 7.x |
|---|---|---|---|---|---|
| Кассандра 1.x | Нет | Нет | Нет | Нет | Нет |
| Cassandra 2.x | Нет | Нет | Нет | Нет | Нет |
| Cassandra 3.x | Нет | Нет | Нет | Нет | Нет |
| Кассандра 4.x | Ограничен | Ограничен | Ограничен | Да | Да |
Этот проект требует Maven и компилирования с Java 8. Чтобы создать плагин, в корне проекта Exepute:
MVN Clean Package
Это построит «все в одну банку» в target/distribution/lib4cassandra
<dependency>
<groupId>com.genesyslab</groupId>
<artifactId>es-index</artifactId>
<version>9.2.000.00</version>
</dependency>
Смотрите пакет GitHub
См. Maven Repository
Поместите es-index-9.2.000.xx-jar-with-dependencies.jar в папку Lib Cassandra вместе с другими банками Cassandra, например, '/usr/are/chare/cassandra/lib' на всех узлах Cassandra. Начните или перезапустите свой узел Cassandra.
Из -за отсутствия тестирования таблицы с кластеризационными клавишами не поддерживаются. Поддерживается только ключ раздела, композитные клавиши разделения должны работать, но не были тщательно протестированы.
Esindex поддерживает только уровень строки TTL, где все ячейки истекают одновременно, и соответствующий документ ES может быть удален одновременно. Если в ряду есть ячейки, которые истекают в разное время, соответствующий документ будет удален, когда истекает последняя ячейка. Если использование различных ячеек TTL, данные, возвращаемые из поиска, все еще будут согласованы, так как данные считываются из SSTables, но все равно будет возможно найти строку, используя истекшие данные, используя запрос ES.
Можно создать несколько индексов на той же таблице, Esindex не предотвратит этого. Однако, если существует более одного EsIndex, поведение может быть противоречивым, такая конфигурация не поддерживается. Команда CQLSH 'Описать таблицу <ks.tablename>' можно использовать для отображения индексов, созданных в таблице, и при необходимости отбросить их.
Для простоты сначала создайте это ключевое пространство:
CREATE KEYSPACE genesys WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}
Давайте использовать ниже таблицы в качестве примера:
CREATE TABLE genesys.emails (
id UUID PRIMARY KEY,
subject text,
body text,
userid int,
query text
);
Вам нужно посвятить фиктивное текстовое столбец для использования индекса. Этот столбец никогда не должен получать данные. В этом примере столбец query - фиктивная колонка.
Вот как создать индекс для примеров таблицы и использовать EseSost для Elasticsearch:
CREATE CUSTOM INDEX ON genesys.emails(query)
USING 'com.genesyslab.webme.commons.index.EsSecondaryIndex'
WITH OPTIONS = {'unicast-hosts': 'eshost:9200'};
Например, если ваш сервер Elasticsearch прослушивает localhost , замените ESHOST на LocalHost .
Ошибки, возвращаемые CQL, очень ограничены, если что -то пойдет не так, как ваш хост Elasticsearch, недоступный, вы получите тайм -аут или другое исключение. Вам придется проверить журналы Cassandra, чтобы понять, что пошло не так.
Мы не предоставили никакого картирования, поэтому мы полагаемся на динамическое картирование Elasticsearch, давайте вставим некоторые данные:
INSERT INTO genesys.emails (id, subject, body, userid)
VALUES (904b88b2-9c61-4539-952e-c179a3805b22, 'Hello world', 'Cassandra is great, but it''s even better with EsIndex and Elasticsearch', 42);
Вы можете видеть, что индекс создается в Elasticsearch, если у вас есть доступ к журналам:
[o.e.c.m.MetaDataCreateIndexService] [node-1] [genesys_emails_index@] creating index, cause [api], templates [], shards [5]/[1], mappings []
[INFO ][o.e.c.m.MetaDataMappingService] [node-1] [genesys_emails_index@/waSGrPvkQvyQoUEiwqKN3w] create_mapping [emails]
Теперь мы можем искать Cassandra с помощью Elasticsearch через индекс, вот поиск синтаксиса Lucene:
select id, subject, body, userid, query from emails where query='body:cassan*';
id | subject | body | userid | query
--------------------------------------+-------------+-------------------------------------------------------------------------+--------+-------
904b88b2-9c61-4539-952e-c179a3805b22 | Hello world | Cassandra is great, but it's even better with EsIndex and Elasticsearch | 42 |
{
"_index": "genesys_emails_index@",
"_type": "emails",
"_id": "904b88b2-9c61-4539-952e-c179a3805b22",
"_score": 0.24257512,
"_source": {
"id": "904b88b2-9c61-4539-952e-c179a3805b22"
},
"took": 4,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.24257512
}
}
(1 rows)
(JSON был отформатирован)
Все строки будут содержать данные из Cassandra, загруженного из SSTables, с использованием согласованности CQL. Данные в столбце «Запрос» - это метаданные, возвращаемые Elasticsearch.
Вот как запросить Elasticsearch, чтобы проверить сгенерированное отображение: GET http://eshost:9200/genesys_emails_index@/emails/_mapping?pretty
{
"genesys_emails_index@" : {
"mappings" : {
"emails" : {
"properties" : {
"IndexationDate" : {
"type" : " date "
},
"_cassandraTtl" : {
"type" : " long "
},
"body" : {
"type" : " text " ,
"fields" : {
"keyword" : {
"type" : " keyword " ,
"ignore_above" : 256
}
}
},
"id" : {
"type" : " text " ,
"fields" : {
"keyword" : {
"type" : " keyword " ,
"ignore_above" : 256
}
}
},
"subject" : {
"type" : " text " ,
"fields" : {
"keyword" : {
"type" : " keyword " ,
"ignore_above" : 256
}
}
},
"userid" : {
"type" : " text " ,
"fields" : {
"keyword" : {
"type" : " keyword " ,
"ignore_above" : 256
}
}
}
}
}
}
}
}Плагин EsIndex добавил два поля:
Мы видим, что отображение выглядит нормально, но Elasticsearch не заметила, что UserId - это целое число и добавленные поля [ключевое слово] для всего текста.
Вот как данные выглядят в Elasticsearch:
GET http://localhost:9200/genesys_emails_index@/emails/_search?pretty&q=body:cassandra
{
"took" : 2 ,
"timed_out" : false ,
"_shards" : {
"total" : 5 ,
"successful" : 5 ,
"skipped" : 0 ,
"failed" : 0
},
"hits" : {
"total" : 1 ,
"max_score" : 0.2876821 ,
"hits" : [
{
"_index" : " genesys_emails_index@ " ,
"_type" : " emails " ,
"_id" : " 904b88b2-9c61-4539-952e-c179a3805b22 " ,
"_score" : 0.2876821 ,
"_source" : {
"id" : " 904b88b2-9c61-4539-952e-c179a3805b22 " ,
"body" : " Cassandra is great, but it's even better with EsIndex and Elasticsearch " ,
"subject" : " Hello world " ,
"userid" : " 42 " ,
"IndexationDate" : " 2019-01-15T16:53:00.107Z " ,
"_cassandraTtl" : 2147483647
}
}
]
}
} Давайте исправим отображение, отказавшись от индекса: drop index genesys.emails_query_idx; Это также выпустит индекс Elasticsearch и данные!
и воссоздайте его с помощью правильного отображения:
CREATE CUSTOM INDEX ON genesys.emails(query)
USING 'com.genesyslab.webme.commons.index.EsSecondaryIndex'
WITH OPTIONS = {
'unicast-hosts': 'localhost:9200',
'mapping-emails': '
{
"emails":{
"date_detection":false,
"numeric_detection":false,
"properties":{
"id":{
"type":"keyword"
},
"userid":{
"type":"long"
},
"subject":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"body":{
"type":"text"
},
"IndexationDate":{
"type":"date",
"format":"yyyy-MM-dd''T''HH:mm:ss.SSS''Z''"
},
"_cassandraTtl":{
"type":"long"
}
}
}
}
'};
Это создаст новый индекс, обеспечит отображение и повторно повторно данных, которые находятся в Кассандре.
Вот полученное отображение ES:
{
"genesys_emails_index@" : {
"mappings" : {
"emails" : {
"date_detection" : false ,
"numeric_detection" : false ,
"properties" : {
"IndexationDate" : {
"type" : " date " ,
"format" : " yyyy-MM-dd'T'HH:mm:ss.SSS'Z' "
},
"_cassandraTtl" : {
"type" : " long "
},
"body" : {
"type" : " text "
},
"id" : {
"type" : " keyword "
},
"subject" : {
"type" : " text " ,
"fields" : {
"keyword" : {
"type" : " keyword " ,
"ignore_above" : 256
}
}
},
"userid" : {
"type" : " long "
}
}
}
}
}
}Теперь, что отображение правильно определено, мы можем искать пользовательский идущий как число. В этом примере мы используем Elasticsearch Query DSL:
select id, subject, body, userid from genesys.emails
where query='{"query":{"range":{"userid":{"gte":10,"lte":50}}}}';
@ Row 1
---------+-------------------------------------------------------------------------
id | 904b88b2-9c61-4539-952e-c179a3805b22
subject | Hello world
body | Cassandra is great, but it's even better with EsIndex and Elasticsearch
userid | 42
Очень важно получить отображение прямо перед началом производства. Повторное нанесение большого стола займет много времени и нанесет значительную нагрузку на Cassandra и Elasticsearch. Вам нужно будет проверить журналы Cassandra на наличие ошибок в вашем картировании ES. Обязательно избежайте отдельных кавычек ('), удвоив их в вариантах JSON, предоставленных команде Create Index.
Ниже приведены все параметры, связанные с конфигурацией индекса Elasticsearch. Ключевые имена могут использовать дефис '-' char или точки. Например, оба имена будут работать:
Обратите внимание, что все параметры ниже относятся к реализации Genesys, а не самим Elasticsearch.
Если классы Jest не найдены, режим фиктивной работы включен, и никакие другие случаи не применяются.
Поддерживается мульти-датранс, и данные реплицируются только через репликацию сплетен Кассандры. Кластеры ES на разных DC не одинаковы и никогда не должны соединяться вместе, или производительность будет затронута. Поскольку данные реплицируются на уровне таблицы, EsIndex получит обновление в каждом DC, а локальный ES Cluster также будет обновлен.

Для поддержки Multi-DC, все параметры могут быть предварительно профиксированы с помощью данных обработки данных и стойки, чтобы сделать настройки местоположения, например:
Чтобы предоставить индекс Cassandra для Elasticsearch с учетными данными, каждый узел должен правильно установить вариабели среды. Это должно быть установлено на всех хозяевах Cassandra.
В приведенном ниже примере приведен пароль для пользователя «Elastic» и Password PassurePassword ', разделенного: (Coll). Это может быть сделано либо непосредственно в системе в качестве переменной среды, либо в ярлыке, которая запускает Cassandra.
Escredentials = Elastic: examplePassword После успешного инициализированного индекса, он напишет «предоставленные учетные данные ElasticSearch» в журналах Cassandra на уровне информации. Как только это сообщение выводится, можно очистить переменную среды. Если Кассандра перезагружена, переменная среды должна быть установлена снова перед запуском. Условия хранятся только в памяти и нигде не сохраняются. Если пользователь и/или пароль изменены, все узлы Cassandra должны быть перезапущены с обновленным значением переменной среды.
В наборе параметров индекса
Unicast-hosts = https : //<host name>:9200
В настоящее время невозможно перенести существующий индекс с HTTP в HTTPS, использование того или иное должно быть решено, прежде чем вы создаете схему Cassandra. Чтобы облегчить развертывание HTTPS, индекс будет автоматически доверять всем сертификатам HTTPS.
Можно сохранить данные на стороне Elasticsearch в течение более длительного периода времени, чем определенный Cassandra TTL. Этот режим поворачивается с использованием опции ES-аналитического режима. Когда опция включена ElasticIndex, пропустит все операции удаления.
Чтобы данные не были слишком расти на стороне ES, рекомендуется использовать настройки TTL-Shift и Force-Delete.
При создании индекса вы будете предоставлять параметры индекса, а также параметры индекса Elasticsearch, используя команду «Использование опции» CQL.
Параметры индекса должны быть указаны при создании индекса, вот пример
CREATE CUSTOM INDEX on genesys.email(query) using 'com.genesyslab.webme.commons.index.EsSecondaryIndex' WITH options =
{
'read-consistency-level':'QUORUM',
'insert-only':'false',
'index-properties': '{
"index.analysis.analyzer.dashless.tokenizer":"dash-ex",
"index.analysis.tokenizer.dash-ex.pattern":"[^\\w\\-]",
"index.analysis.tokenizer.dash-ex.type":"pattern"
}',
'mapping-email': '{
"email": {
"dynamic": "false",
"properties": {
"subject" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}',
'discard-nulls':'false',
'async-search':'true',
'async-write':'false'
};
Вы также можете установить или переопределить параметры, используя переменные среды или свойства Java System, путем префикса с помощью «Genesys-es-».
Сначала используются параметры, представленные в команде «Создать пользовательский индекс». Они могут быть локально переопределены, используя файл с именем es-index.properties , найденные в ".", "./Conf/", ".../conf/" или "./bin/". (можно изменить с помощью -dgenesys-esi-e-file или -dgenesys.es.esi.file System)
Вот пример для содержания файла:
INSERT-ONLY = TRUE DISCARD NULLS = FALSE ASYNCWRITE = FALSE
| Имя | По умолчанию | Описание |
|---|---|---|
| максимум | 10000 | Количество результатов для чтения из поиска ES для загрузки рядов Cassandra. |
| Уровень чтения-согласованности | ОДИН | Используемый для поиска, этот уровень согласованности используется для загрузки рядов Cassandra. |
| только вставка | ЛОЖЬ | По умолчанию Esindex будет использовать операции Upsert. В INSERT MODE Данные всегда будут перезаписаны. |
| асинк-писатель | истинный | Отправляет индексные обновления асинхронно, не проверяя правильное выполнение. Это обеспечивает гораздо более быстрые записи, но данные могут стать непоследовательными, если ES Cluster недоступен, потому что записи не пройдут. По умолчанию верно. |
| сегмент | ВЫКЛЮЧЕННЫЙ | OFF, час, день, месяц, год, пользовательская сегментация автоматического индекса контролируется этой настройкой. В случае установки в день, каждый день под псевдонимом будет создан новый индекс. Обратите внимание, что пустые индексы удаляются автоматически каждый час. Примечание. Настройка часа не рекомендуется, поскольку он создаст много индексов и может снизить производительность. Этот параметр рекомендуется для целей разработки и тестирования. |
| имени сегмента | Если сегмент = пользовательское это значение будет использоваться для нового индекса. | |
| Картирование- <Тип> | {} | Для каждого вторичного индекса имя таблицы передается как тип, например, mapping-visit = {json определение}. |
| одноадресные хосты | http: // localhost: 9200 | Отдельный список хоста может быть host1, host2, host3 или http: // host1, http: // host2, http: // host3 или http: // host1: 9200, http: // host2: 9200, http: // host3: 9200. Если протокол или порт отсутствуют HTTP и 9200. Можно использовать HTTPS. |
| выбросить ноль | истинный | Не передайте нулевые значения ES Index, это означает, что вы не сможете удалить значение. По умолчанию верно . |
| Индекс-пропертистики | {} | Свойства как строки JSON, передаваемая для создания нового индекса, могут содержать, например, определения токенизатора. |
| JSON-Serialized-Fields | {} | Кома разделенная строка, определяющая, что строковый столбец должен быть проиндексирован как строка JSON. Несоответствующие строки предотвратят вставки в Кассандру. |
| JSON-FLAT-SERIALIZET-FIELDS | {} | Кома разделенная строка, определяющая, что строковый столбец должен быть проиндексирован в виде документа JSON, безопасного типа. Elasticsearch Json Mapping не позволяет индексировать значение, которое будет изменяться с течением времени. Например, {"key": "value"} не может стать {"ключ": {"soopkey": "value"}} В ElasticSearch вы получите исключение сопоставления. Такой JSON-Flat будет преобразователем в объект JSON, у которого есть струнные клавиши и массивы строки в качестве значений. |
| дурачок | ЛОЖЬ | Полностью отключает вторичный индекс. Обратите внимание, что если классы Jest не найдены, индекс будет автоматически помещать в фиктивный режим. |
| проверка-Queries | ЛОЖЬ | Отправляет запросы поиска в ES для проверки, чтобы предоставить значимые синтаксические ошибки вместо тайм -аутов Cassandra. |
| одновременно-блокировка | истинный | Заблокированные индексы выполнения на идентификатор раздела. Это предотвращает проблемы с параллелизмом при работе с несколькими обновлениями на одном и том же разделе одновременно. |
| Skip-Log-Replay | истинный | Когда начнутся узлы Cassandra, он воспроизводит журнал коммит, эти обновления пропускаются для улучшения времени запуска, поскольку они уже применяются к ES. |
| Скип-нон-локальные обновления | истинный | Чтобы улучшить производительность, включающая эту настройку только выполнять обновления индекса в мастер -копии диапазона токенов. |
| ES-аналитический режим | ЛОЖЬ | Отключает удаления (TTL или удаление из) документов ES. |
| Тип-пипелина | никто | Список типа для настройки трубопроводов. |
| трубопровод- <Тип> | никто | Определение трубопровода для этого типа. |
| index.translog.durability | асинхро | При создании индекса мы используем режим Async Commit для обеспечения наилучшей производительности, это была настройка по умолчанию в ES 1.7. Поскольку 2.x это синхронизация, приводящая к серьезному деградации производительности. |
| Доступно, While-Rebuilding | истинный | При создании нового индекса можно (или нет) запускать поиски по частичному индексу. |
| уселка | ЛОЖЬ | Усекайте индекс ES перед восстановлением. |
| чистка | 60 | Каждые 60 минут все пустые индексы будут удалены из псевдонима. |
| за индекс | истинный | Приготовьте имя индекса с именем таблицы. В ES 5.x больше невозможно иметь другое отображение для одного имени поля в разных типах одного и того же индекса. В ES 6.x типы будут удалены. |
| Сила-делек | ЛОЖЬ | Каждую минуту запрос «Удалить запрос» отправляется в ES для удаления документов, которые истекли _cassandrattl. Это для эмуляции функциональности TTL, которая была удалена в ES 5.x. Обратите внимание, что, хотя Cassandra Compaction фактически удалит документ из ES, нет никакой гарантии, когда это произойдет. |
| TTL-сдвиг | 0 | Время за несколько секунд, чтобы изменить Кассандру Ттл. Если TTL был 1 ч в Кассандре, а сдвиг - 3600, это означает, что документ в ES будет удален на 1 ч. Позже Кассандра. |
| Индекс-менеджер | com.genesyslab.webme.commons.index.defaultindexmanager | Имя класса индекса. Используется для менеджера сегментации и функциональности истечения срока действия. |
| Размер сегмента | 86400000 | Сроки сегмента в миллисекундах. Каждый «Размер сегмента» Milliseconds Новый индекс будет создан путем следующего шаблона: <alias_name> _index@<yyyymmdd't'hhmmss'z '> |
| Максимальные соединения в маршруте | 2 | Количество подключения HTTP на ES Node, по умолчанию - значение Pool Apache HTTP, может повысить производительность индекса Cassandra, но увеличить нагрузку на ES. (Новое в WCC 9.0.000.15) |
Вы должны отключить обнаружение даты в определении картирования.
Следующий JSON:
{
"maps" : {
"key1" : " value " ,
"key2" : 42 ,
"keymap" : {
"sss1" : null ,
"sss2" : 42 ,
"sss0" : " ffff "
},
"plap" : " plop "
},
"string" : " string " ,
"int" : 42 ,
"plplpl" : [ 1 , 2 , 3 , 4 ]
}Будет преобразован в:
{
"maps" : [ " key1=value " , " key2=42 " , " keymap={sss1=null, sss2=42, sss0=ffff} " , " plap=plop " ],
"string" : [ " string " ],
"int" : [ " 42 " ],
"plplpl" : [ " 1 " , " 2 " , " 3 " , " 4 " ]
}Возможные значения:
<type>Смотрите документацию ElasticSearch для получения подробной информации о типовом отображении: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping.html
Все типы столбцов Cassandra поддерживаются, данные будут отправлены в виде строки, массива или карты в зависимости от типа Cassandra. При правильном отображении Elasticsearch затем преобразует данные в соответствующий тип. Это позволит гораздо лучшие поиски и отчетность.
| Типы Кассандры | Elasticsearch рекомендовал картирование | Комментарий |
|---|---|---|
| Асии | текст или ключевое слово | См. Следующий раздел по типу текста |
| bigint | длинный | |
| капля | неполноценный | Невозможно индексировать бинарный контент |
| логический | логический | |
| прилавок | длинный | |
| дата | дата | |
| Десятичный | двойной | |
| двойной | двойной | |
| плавать | двойной | |
| inet | ключевое слово | ES IP не тестируется |
| инт | инт | |
| Список <IPER> | То же, что и тип | ES ожидает, что тип может быть либо единственным значением, либо массивом |
| Карта < typek , typev > | объект | Если ваши ключи могут иметь много разных значений, остерегайтесь картирования взрыва |
| Установите < Тип > | То же, что и тип | ES ожидает, что тип может быть либо единственным значением, либо массивом |
| Smallint | инт | |
| текст | текст или ключевое слово | См. Следующий раздел по типу текста |
| время | ключевое слово | |
| временная метка | «Тип»: «дата», «формат»: «yyyy-mm-dd'hh: mm: ss.sss'z» | |
| время | ключевое слово | |
| Tinyint | инт | |
| Тупел <type1 type2, ...> | тип | |
| uuid | ключевое слово | |
| варчар | текст или ключевое слово | См. Следующий раздел по типу текста |
| вариант | длинный | |
| Пользовательский тип | объект | Каждое поле UDT будет сопоставлено с использованием их имен и значений |
Картирование типа текста
Когда столбец текста (ASCII или Varchar) отправляется в ES, он отправляется в виде необработанного текста для индексации. Однако, если текст является правильным JSON, можно отправить его в качестве документа JSON для индекса. Это позволяет индексировать/искать документ вместо необработанного текста.
Использование такого отображения JSON позволяет искать данные с использованием «columnName.key: value».
Если ваши ключи могут иметь много разных значений, остерегайтесь картирования взрыва
json-serialized-fields (подробности см. Параметры).
Содержание текста отправляется как JSON. В вашем отображении вы можете определить каждое поле документа отдельно. Обратите внимание, что после того, как поле будет отображено как тип, либо с помощью статического отображения, либо динамического картирования, обеспечение несовместимого типа приведет к отказу от записи Cassandra.
GSON-Flat-Serialized-Fields (см. Параметры для получения подробной информации и примера преобразования)
Содержание текста также отправляется в качестве JSON, однако все значения вынуждены массивы плоских струн. Это ограничит способность искать в вложенном JSON, но будет безопаснее, если вы не можете контролировать тип значений JSON.
Это пользовательская реализация индекса Cassandra. Это вводит некоторые ограничения, связанные с моделью согласованности Cassandra. Основное ограничение связано с характером вторичных индексов Cassandra, каждый узел Cassandra содержит только данные, которые он отвечает в кольце Cassandra, а вторичные индексы это одно и то же, каждый узел только индексирует его локальные данные. Это означает, что при выполнении запроса по индексу запрос отправляется на все узлы, а затем результаты агрегируются координатором запроса и возвращаются клиентам.
С Esindex это отличается, поскольку поиск индекса основан на Elasticsearch, каждый узел способен отвечать на запрос. Это означает, что запрос должен быть отправлен только в один узел или результат будет содержать дубликаты. Это достигается путем привлечения токена к запросу CQL, как и ниже.
select * from emails where query='subject:12345' and token(id)=0;
Токен должен быть любым случайным длинным значением для распространения запросов по узлам. Он должен быть построен на ключе раздела строки «ID» в приведенном выше примере.
В приведенном выше примере запрос Elasticsearch - «Тема: 12345». Это Lucene, похожий на запрос. Также можно выполнить DSL-запросы, см. Elasticsearch Query-DSL страница для получения более подробной информации.
Один индекс Elasticsearch будет содержать все индексы таблицы Cassandra для данного ключа. Для каждого индекса используется выделенный тип Elasticsearch. Чтобы разрешить агрегации с перекрестным столом, тип не применяется в запросах. Это означает, что если ваш запрос может соответствовать различным типам, он вернет больше идентификаторов, чем ожидалось. Поскольку они не будут соответствовать рядам Cassandra, вы не получите больше результатов, но вы также можете получить меньше, если вы ограничиваете количество возвращаемых результатов.
Если соответствующий счет строк высокий, а ряды велики, поиски могут заканчиваться в прочтении тайм-аута. Вы можете запросить только PK, чтобы быть возвращенным с помощью ES Metadata, а затем загружать строки параллельно из вашего кода с помощью запросов CQL.
Чтобы сообщить индексу, чтобы вернуть PK, только вам нужно использовать приведенный ниже запрос #OPTIONS: LOAD-ROWS = FALSE #:
select * from emails where query='#options:load-rows=false#id:ab*';
Важно отметить, что возвращаемые ряды являются поддельными и построены из результатов запроса Elasicsearch. Это означает, что возвращенные ряды могут больше не существовать:
Хен, запрос на поиск возвращает результат, первая строка будет содержать метаданные Elasticsearch как ## string json в столбце индекса. Смотрите, например:
cqlsh:ucs> select id,query from emails where query='id:00008RD9PrJMMmpr';
id | query
------------------+---------------------------------------------------------------------------------------------------------------------
00008RD9PrJMMmpr | {"took":5,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":1,"max_score":7.89821}}
Механизм сегментации EsIndex разбивает монолитный индекс Elasticsearch на последовательность индексов, основанных на времени. Цели для этого следующие:
Поскольку Elasticsearch 5.x TTL больше не поддерживается. Однако нормальные процессы уплотнения и ремонта Cassandra автоматически удаляют данные надгробной плиты, ElasticIndex удалит данные из Elasticsearch.
EsIndex поддерживает трассировку CQL, его можно включить на узле или использовать CQLSH с помощью команды ниже:
Отслеживание;
Трассирование выбирает, тогда вы получите следы от всего запроса против всех участвующих узлов:
cqlsh:ucs> select * from "Contact" where "ESQuery"='AttributeValues.LastName:ab*' and token("Id")=0 limit 1;
Id | AttributeValues | AttributeValuesDate | Attributes| CreatedDate | ESQuery | ExpirationDate | MergeIds | ModifiedDate| PrimaryAttributes| Segment| TenantId
1001uiP2niJPJGBa | {"LastName":["IdentifyTest-aBEcKPnckHVP"],"EmailAddress":["IdentifyTest-HHzmNornOr"]} |{} | {'EmailAddress_IdentifyTest-HHzmNornOr': {Id: 'EmailAddress_IdentifyTest-HHzmNornOr', Name: 'EmailAddress', StrValue: 'IentifyTest-HHzmNornOr', Description: null, MimeType: null, IsPrimary: False}, 'LastName_IdentifyTest-aBEcKPnckHVP': {Id: 'LastName_IdentifyTest-aBEcKPnckHVP', Name: 'LastName', StrValue: 'IdentifyTest-aBEcKPnckHVP', Description: null, MimeType: null IsPrimary: False}} | 2018-10-30 02:05:06.960000+0000 | {"_index":"ucsperf2_contact_index@","_type":"Contact","_id":"1001uiP2niJPJGBa","_score":1.0,"_source":{"Id":"1001uiP2niJPJGBa"},"took":485,"timed_out":false,"_shards":{"total":5,"successful":5,failed":0},"hits":{"total":18188,"max_score":1.0}} | null | null | 2018-10-30 02:05:06.960000+0000 | {'EmailAddress': 'IdentifyTest-HHzmNornOr', 'LastName': 'IdentifyTest-aBEcKPnckHVP'} | not-applicable |1
(1 rows)
Тогда вы получите информацию о отслеживании от своего сеанса:
Сессия трассировки: 8ED07B60-180D-11E9-B832-33A777983333
activity | timestamp | source | source_elapsed | client
-----------------------------------------------------------------------------------------------------------------------------------------+----------------------------+---------------+----------------+--------------
Execute CQL3 query | 2019-01-14 16:03:32.118000 | xxx.xx.47.82 | 0 | xxx.xx.40.11
RANGE_SLICE message received from /xxx.xx.47.82 [MessagingService-Incoming-/xxx.xx.47.82] | 2019-01-14 16:02:30.200000 | xxx.xx.47.49 | 34 | xxx.xx.40.11
Executing read on ucsperf2.Contact using index Contact_ESQuery_idx [ReadStage-1] | 2019-01-14 16:02:30.201000 | xxx.xx.47.49 | 411 | xxx.xx.40.11
ESI 00ebf964-b958-4e74-ab89-e0093a8ec188 Searching 'AttributeValues.LastName:ab*' [ReadStage-1] | 2019-01-14 16:02:30.201000 | xxx.xx.47.49 | 693 | xxx.xx.40.11
ESI 00ebf964-b958-4e74-ab89-e0093a8ec188 Found 10000 matching ES docs in 514ms [ReadStage-1] | 2019-01-14 16:02:30.716000 | xxx.xx.47.49 | 515336 | xxx.xx.40.11
ESI 00ebf964-b958-4e74-ab89-e0093a8ec188 StreamingPartitionIterator initialized [ReadStage-1] | 2019-01-14 16:02:30.717000 | xxx.xx.47.49 | 516911 | xxx.xx.40.11
reading data from /xxx.xx.47.100 [ReadStage-1] | 2019-01-14 16:02:30.717000 | xxx.xx.47.49 | 517121 | xxx.xx.40.11
speculating read retry on /xxx.xx.47.82 [ReadStage-1] | 2019-01-14 16:02:30.718000 | xxx.xx.47.49 | 517435 | xxx.xx.40.11
Executing single-partition query on Contact [ReadStage-2] | 2019-01-14 16:02:30.718000 | xxx.xx.47.49 | 517436 | xxx.xx.40.11
Sending READ message to /xxx.xx.47.100 [MessagingService-Outgoing-/xxx.xx.47.100-Small] | 2019-01-14 16:02:30.718000 | xxx.xx.47.49 | 517445 | xxx.xx.40.11
Sending READ message to /xxx.xx.47.82 [MessagingService-Outgoing-/xxx.xx.47.82-Small] | 2019-01-14 16:02:30.718000 | xxx.xx.47.49 | 517558 | xxx.xx.40.11
Acquiring sstable references [ReadStage-2] | 2019-01-14 16:02:30.718000 | xxx.xx.47.49 | 517866 | xxx.xx.40.11
Bloom filter allows skipping sstable 83 [ReadStage-2] | 2019-01-14 16:02:30.718000 | xxx.xx.47.49 | 517965 | xxx.xx.40.11
Partition index with 0 entries found for sstable 400 [ReadStage-2] | 2019-01-14 16:02:30.719000 | xxx.xx.47.49 | 518300 | xxx.xx.40.11
REQUEST_RESPONSE message received from /xxx.xx.47.82 [MessagingService-Incoming-/xxx.xx.47.82] | 2019-01-14 16:02:30.720000 | xxx.xx.47.49 | 519720 | xxx.xx.40.11
Processing response from /xxx.xx.47.82 [RequestResponseStage-4] | 2019-01-14 16:02:30.720000 | xxx.xx.47.49 | 519865 | xxx.xx.40.11
Bloom filter allows skipping sstable 765 [ReadStage-2] | 2019-01-14 16:02:30.723000 | xxx.xx.47.49 | 522352 | xxx.xx.40.11
Bloom filter allows skipping sstable 790 [ReadStage-2] | 2019-01-14 16:02:30.723000 | xxx.xx.47.49 | 522451 | xxx.xx.40.11
Bloom filter allows skipping sstable 819 [ReadStage-2] | 2019-01-14 16:02:30.723000 | xxx.xx.47.49 | 522516 | xxx.xx.40.11
Bloom filter allows skipping sstable 848 [ReadStage-2] | 2019-01-14 16:02:30.723000 | xxx.xx.47.49 | 522662 | xxx.xx.40.11
Bloom filter allows skipping sstable 861 [ReadStage-2] | 2019-01-14 16:02:30.723000 | xxx.xx.47.49 | 522741 | xxx.xx.40.11
Skipped 0/7 non-slice-intersecting sstables, included 0 due to tombstones [ReadStage-2] | 2019-01-14 16:02:30.723000 | xxx.xx.47.49 | 522855 | xxx.xx.40.11
Merged data from memtables and 1 sstables [ReadStage-2] | 2019-01-14 16:02:30.723001 | xxx.xx.47.49 | 523075 | xxx.xx.40.11
Read 1 live and 0 tombstone cells [ReadStage-2] | 2019-01-14 16:02:30.723001 | xxx.xx.47.49 | 523164 | xxx.xx.40.11
Read 1 live and 0 tombstone cells [ReadStage-1] | 2019-01-14 16:02:30.725000 | xxx.xx.47.49 | 524717 | xxx.xx.40.11
ESI 00ebf964-b958-4e74-ab89-e0093a8ec188 StreamingPartitionIterator closed [ReadStage-1] | 2019-01-14 16:02:30.725000 | xxx.xx.47.49 | 524805 | xxx.xx.40.11
Enqueuing response to /xxx.xx.47.82 [ReadStage-1] | 2019-01-14 16:02:30.725000 | xxx.xx.47.49 | 524872 | xxx.xx.40.11
Sending REQUEST_RESPONSE message to /xxx.xx.47.82 [MessagingService-Outgoing-/xxx.xx.47.82-Small] | 2019-01-14 16:02:30.725000 | xxx.xx.47.49 | 524971 | xxx.xx.40.11
REQUEST_RESPONSE message received from /xxx.xx.47.100 [MessagingService-Incoming-/xxx.xx.47.100] | 2019-01-14 16:02:30.729000 | xxx.xx.47.49 | 528222 | xxx.xx.40.11
Processing response from /xxx.xx.47.100 [RequestResponseStage-1] | 2019-01-14 16:02:30.729000 | xxx.xx.47.49 | 528364 | xxx.xx.40.11
Initiating read-repair [RequestResponseStage-1] | 2019-01-14 16:02:30.729000 | xxx.xx.47.49 | 528481 | xxx.xx.40.11
Parsing select * from "Contact" where "ESQuery"='AttributeValues.LastName:ab*' and token("Id")=0 limit 1; [Native-Transport-Requests-1] | 2019-01-14 16:03:32.119000 | xxx.xx.47.82 | 174 | xxx.xx.40.11
Preparing statement [Native-Transport-Requests-1] | 2019-01-14 16:03:32.119000 | xxx.xx.47.82 | 254 | xxx.xx.40.11
Index mean cardinalities are Contact_ESQuery_idx:-2109988917941223823. Scanning with Contact_ESQuery_idx. [Native-Transport-Requests-1] | 2019-01-14 16:03:32.119000 | xxx.xx.47.82 | 418 | xxx.xx.40.11
Computing ranges to query [Native-Transport-Requests-1] | 2019-01-14 16:03:32.121000 | xxx.xx.47.82 | 2480 | xxx.xx.40.11
Submitting range requests on 1 ranges with a concurrency of 1 (-4.6099044E15 rows per range expected) [Native-Transport-Requests-1] | 2019-01-14 16:03:32.121000 | xxx.xx.47.82 | 2568 | xxx.xx.40.11
Enqueuing request to /xxx.xx.47.49 [Native-Transport-Requests-1] | 2019-01-14 16:03:32.121000 | xxx.xx.47.82 | 2652 | xxx.xx.40.11
Submitted 1 concurrent range requests [Native-Transport-Requests-1] | 2019-01-14 16:03:32.121000 | xxx.xx.47.82 | 2708 | xxx.xx.40.11
Sending RANGE_SLICE message to /xxx.xx.47.49 [MessagingService-Outgoing-/xxx.xx.47.49-Small] | 2019-01-14 16:03:32.121000 | xxx.xx.47.82 | 2874 | xxx.xx.40.11
READ message received from /xxx.xx.47.49 [MessagingService-Incoming-/xxx.xx.47.49] | 2019-01-14 16:03:32.640000 | xxx.xx.47.100 | 29 | xxx.xx.40.11
READ message received from /xxx.xx.47.49 [MessagingService-Incoming-/xxx.xx.47.49] | 2019-01-14 16:03:32.640000 | xxx.xx.47.82 | 521263 | xxx.xx.40.11
Executing single-partition query on Contact [ReadStage-2] | 2019-01-14 16:03:32.640000 | xxx.xx.47.82 | 521468 | xxx.xx.40.11
Acquiring sstable references [ReadStage-2] | 2019-01-14 16:03:32.640000 | xxx.xx.47.82 | 521566 | xxx.xx.40.11
Partition index with 0 entries found for sstable 1187 [ReadStage-2] | 2019-01-14 16:03:32.640000 | xxx.xx.47.82 | 521775 | xxx.xx.40.11
Executing single-partition query on Contact [ReadStage-1] | 2019-01-14 16:03:32.641000 | xxx.xx.47.100 | 266 | xxx.xx.40.11
Bloom filter allows skipping sstable 1188 [ReadStage-2] | 2019-01-14 16:03:32.641000 | xxx.xx.47.82 | 522130 | xxx.xx.40.11
Acquiring sstable references [ReadStage-1] | 2019-01-14 16:03:32.641000 | xxx.xx.47.100 | 361 | xxx.xx.40.11
Bloom filter allows skipping sstable 1189 [ReadStage-2] | 2019-01-14 16:03:32.641000 | xxx.xx.47.82 | 522205 | xxx.xx.40.11
Bloom filter allows skipping sstable 1190 [ReadStage-2] | 2019-01-14 16:03:32.641000 | xxx.xx.47.82 | 522259 | xxx.xx.40.11
Skipped 0/5 non-slice-intersecting sstables, included 0 due to tombstones [ReadStage-2] | 2019-01-14 16:03:32.641001 | xxx.xx.47.82 | 522303 | xxx.xx.40.11
Bloom filter allows skipping sstable 1186 [ReadStage-2] | 2019-01-14 16:03:32.641001 | xxx.xx.47.82 | 522415 | xxx.xx.40.11
Merged data from memtables and 1 sstables [ReadStage-2] | 2019-01-14 16:03:32.641001 | xxx.xx.47.82 | 522540 | xxx.xx.40.11
Read 1 live and 0 tombstone cells [ReadStage-2] | 2019-01-14 16:03:32.641001 | xxx.xx.47.82 | 522679 | xxx.xx.40.11
Enqueuing response to /xxx.xx.47.49 [ReadStage-2] | 2019-01-14 16:03:32.641001 | xxx.xx.47.82 | 522734 | xxx.xx.40.11
Sending REQUEST_RESPONSE message to /xxx.xx.47.49 [MessagingService-Outgoing-/xxx.xx.47.49-Small] | 2019-01-14 16:03:32.641001 | xxx.xx.47.82 | 522863 | xxx.xx.40.11
Partition index with 0 entries found for sstable 1208 [ReadStage-1] | 2019-01-14 16:03:32.644000 | xxx.xx.47.100 | 3756 | xxx.xx.40.11
REQUEST_RESPONSE message received from /xxx.xx.47.49 [MessagingService-Incoming-/xxx.xx.47.49] | 2019-01-14 16:03:32.647000 | xxx.xx.47.82 | 528443 | xxx.xx.40.11
Processing response from /xxx.xx.47.49 [RequestResponseStage-2] | 2019-01-14 16:03:32.647000 | xxx.xx.47.82 | 528516 | xxx.xx.40.11
Bloom filter allows skipping sstable 1209 [ReadStage-1] | 2019-01-14 16:03:32.649000 | xxx.xx.47.100 | 9090 | xxx.xx.40.11
Bloom filter allows skipping sstable 1210 [ReadStage-1] | 2019-01-14 16:03:32.649000 | xxx.xx.47.100 | 9162 | xxx.xx.40.11
Bloom filter allows skipping sstable 1211 [ReadStage-1] | 2019-01-14 16:03:32.649000 | xxx.xx.47.100 | 9187 | xxx.xx.40.11
Skipped 0/5 non-slice-intersecting sstables, included 0 due to tombstones [ReadStage-1] | 2019-01-14 16:03:32.650000 | xxx.xx.47.100 | 9237 | xxx.xx.40.11
Bloom filter allows skipping sstable 1207 [ReadStage-1] | 2019-01-14 16:03:32.650000 | xxx.xx.47.100 | 9335 | xxx.xx.40.11
Merged data from memtables and 1 sstables [ReadStage-1] | 2019-01-14 16:03:32.650000 | xxx.xx.47.100 | 9571 | xxx.xx.40.11
Read 1 live and 0 tombstone cells [ReadStage-1] | 2019-01-14 16:03:32.650000 | xxx.xx.47.100 | 9734 | xxx.xx.40.11
Enqueuing response to /xxx.xx.47.49 [ReadStage-1] | 2019-01-14 16:03:32.650000 | xxx.xx.47.100 | 9842 | xxx.xx.40.11
Sending REQUEST_RESPONSE message to /xxx.xx.47.49 [MessagingService-Outgoing-/xxx.xx.47.49-Small] | 2019-01-14 16:03:32.650000 | xxx.xx.47.100 | 10116 | xxx.xx.40.11
Request complete | 2019-01-14 16:03:32.646708 | xxx.xx.47.82 | 528708 | xxx.xx.40.11
Все виды деятельности, начиная с ESI, являются мероприятиями от EsIndex:
* ESI <id> Searching 'AttributeValues.LastName:ab*': The query have been received and decoded by the ESIndex, it is now sent to ElasticSearch
* ESI <id> Found 10000 matching ES docs in 514ms: The query to ElasticSearch has found 10000 results
* ESI <id> StreamingPartitionIterator initialized: Streaming partition iterator have been provided with all Ids found, and starts reading rows
* ESI <id> StreamingPartitionIterator closed: Client is done reading rows (limit was 1)
Трассирование обновлений/вставки/удаления
cqlsh:ucs> update "Contact" set "CreatedDate"='2017-04-01T11:21:59.001+0000' where "Id"='1001uiP2niJPJGBa';
Сессия трассировки: F76E4AC0-180E-11E9-B832-33A777983333
activity | timestamp | source | source_elapsed | client
----------------------------------------------------------------------------------------------------------------------------------------+----------------------------+---------------+----------------+--------------
Execute CQL3 query | 2019-01-14 16:13:37.132000 | xxx.xx.47.82 | 0 | xxx.xx.40.11
MUTATION message received from /xxx.xx.47.82 [MessagingService-Incoming-/xxx.xx.47.82] | 2019-01-14 16:12:35.210000 | xxx.xx.47.49 | 22 | xxx.xx.40.11
Appending to commitlog [MutationStage-1] | 2019-01-14 16:12:35.210000 | xxx.xx.47.49 | 354 | xxx.xx.40.11
Adding to Contact memtable [MutationStage-1] | 2019-01-14 16:12:35.210000 | xxx.xx.47.49 | 465 | xxx.xx.40.11
Enqueuing response to /xxx.xx.47.82 [MutationStage-1] | 2019-01-14 16:12:35.212000 | xxx.xx.47.49 | 2356 | xxx.xx.40.11
Sending REQUEST_RESPONSE message to /xxx.xx.47.82 [MessagingService-Outgoing-/xxx.xx.47.82-Small] | 2019-01-14 16:12:35.212000 | xxx.xx.47.49 | 2548 | xxx.xx.40.11
Parsing update "Contact" set "CreatedDate"='2017-04-01T11:21:59.001+0000' where "Id"='1001uiP2niJPJGBa'; [Native-Transport-Requests-1] | 2019-01-14 16:13:37.132000 | xxx.xx.47.82 | 146 | xxx.xx.40.11
Preparing statement [Native-Transport-Requests-1] | 2019-01-14 16:13:37.132000 | xxx.xx.47.82 | 213 | xxx.xx.40.11
Determining replicas for mutation [Native-Transport-Requests-1] | 2019-01-14 16:13:37.133000 | xxx.xx.47.82 | 1895 | xxx.xx.40.11
Appending to commitlog [MutationStage-2] | 2019-01-14 16:13:37.134000 | xxx.xx.47.82 | 2042 | xxx.xx.40.11
Adding to Contact memtable [MutationStage-2] | 2019-01-14 16:13:37.134000 | xxx.xx.47.82 | 2149 | xxx.xx.40.11
Sending MUTATION message to /xxx.xx.47.100 [MessagingService-Outgoing-/xxx.xx.47.100-Small] | 2019-01-14 16:13:37.134000 | xxx.xx.47.82 | 2186 | xxx.xx.40.11
Sending MUTATION message to /xxx.xx.47.49 [MessagingService-Outgoing-/xxx.xx.47.49-Small] | 2019-01-14 16:13:37.134000 | xxx.xx.47.82 | 2232 | xxx.xx.40.11
MUTATION message received from /xxx.xx.47.82 [MessagingService-Incoming-/xxx.xx.47.82] | 2019-01-14 16:13:37.136000 | xxx.xx.47.100 | 28 | xxx.xx.40.11
Appending to commitlog [MutationStage-1] | 2019-01-14 16:13:37.136000 | xxx.xx.47.100 | 390 | xxx.xx.40.11
Adding to Contact memtable [MutationStage-1] | 2019-01-14 16:13:37.136000 | xxx.xx.47.100 | 471 | xxx.xx.40.11
ESI decoding row 31303031756950326e694a504a474261 [MutationStage-1] | 2019-01-14 16:13:37.137000 | xxx.xx.47.100 | 579 | xxx.xx.40.11
REQUEST_RESPONSE message received from /xxx.xx.47.49 [MessagingService-Incoming-/xxx.xx.47.49] | 2019-01-14 16:13:37.137000 | xxx.xx.47.82 | 5160 | xxx.xx.40.11
ESI writing 31303031756950326e694a504a474261 to ES index [MutationStage-1] | 2019-01-14 16:13:37.137000 | xxx.xx.47.100 | 664 | xxx.xx.40.11
Processing response from /xxx.xx.47.49 [RequestResponseStage-4] | 2019-01-14 16:13:37.137000 | xxx.xx.47.82 | 5280 | xxx.xx.40.11
ESI index 31303031756950326e694a504a474261 done [MutationStage-1] | 2019-01-14 16:13:37.160000 | xxx.xx.47.100 | 23878 | xxx.xx.40.11
REQUEST_RESPONSE message received from /xxx.xx.47.100 [MessagingService-Incoming-/xxx.xx.47.100] | 2019-01-14 16:13:37.160000 | xxx.xx.47.82 | 28445 | xxx.xx.40.11
Processing response from /xxx.xx.47.100 [RequestResponseStage-2] | 2019-01-14 16:13:37.160000 | xxx.xx.47.82 | 28549 | xxx.xx.40.11
Enqueuing response to /xxx.xx.47.82 [MutationStage-1] | 2019-01-14 16:13:37.162000 | xxx.xx.47.100 | 25614 | xxx.xx.40.11
Sending REQUEST_RESPONSE message to /xxx.xx.47.82 [MessagingService-Outgoing-/xxx.xx.47.82-Small] | 2019-01-14 16:13:37.162000 | xxx.xx.47.100 | 25793 | xxx.xx.40.11
Request complete | 2019-01-14 16:13:37.814048 | xxx.xx.47.82 | 682048 | xxx.xx.40.11
Все виды деятельности, начиная с ESI, являются мероприятиями от EsIndex:
* ESI decoding row <rowId>: update request have been received by the ESIndex, row is being converted to JSON
* ESI writing <rowId> to ES index: update is being sent to ElasticSearch
* ESI index <rowId> done: ElasticSearch acknowledged the update
Это пример того, что происходит при поиске:

Это пример синхронной записи (операция Cassandra потерпит неудачу, если ES не удастся):

Это пример асинхронной записи:

Это пример асинхронной записи, операция Cassandra не удастся, если ES не удается:
