У нас есть таблица Hbase, в которой ключ строки подготовлен путем объединения сайта и статьи, т. е. если у меня есть сайт A, который продает 100 200 300 артикулов. Мои строки - A100, A200, A300 соответственно. Теперь мы хотим просканировать таблицу hbase, используя только артикул. Который может присутствовать на нескольких сайтах. Мы попытались выполнить сканирование с помощью компаратора подстрок. Но это занимает много времени. Может ли кто-нибудь предложить лучший дизайн соления или рядного ключа для того же сценария.

-1
Prathamesh H 11 Дек 2019 в 07:49

1 ответ

Не похоже, что эта проблема может быть решена простым изменением дизайна строки, пока вы не сможете поменять местами SiteId и ArticleId, но в этом случае у вас будет такая же проблема с поиском по SiteId. Причина такого поведения в том, что HBase никак не может оптимизировать поиск по средней или последней части ключей и вынужден делать полное сканирование.

Некоторые решения, которые вы могли бы придумать:
1. Сделайте несколько одновременных поисков по одному на каждый сайт с условием rowkey == SiteIdArticleId. Это будет работать быстро, если у вас относительно небольшое количество сайтов.
2. Выполните custom secondary index. Вторая индексная таблица с AtricleId в качестве ключа строки и SiteId в качестве значений продажи.
3. Используйте Apache Phoenix, который может выполнять вторичное индексирование "из коробки". (Но сначала проверьте, подходит ли он вам)

Во втором случае вы можете выполнить получение по ключу из индексной таблицы, а затем от нуля до нескольких значений для каждой ячейки из первого получения. Это будет работать довольно быстро, но потребует некоторого пространства.

Подробнее о втором варианте:

Предположим, что ваша таблица собрана SiteToArticle, а вторая таблица собрана ArticleToSite Когда вы делаете записи, вы пишете в обе таблицы, в первую, как обычно, и во вторую, как {"rowkey"=ArticleId, "SiteId"=siteId}

Когда вы выполняете чтение, сначала вы читаете из ArticleToSite, затем выполняете итерацию по каждому SiteId, создаете новый get с ключом SiteId:ArticleId и выполняете второй пакет get. Код может выглядеть примерно так:

byte[] articleId = "ArticleId".getBytes();
Get get = new Get(articleId).readAllVersions();
Table t = connection.getTable(TableName.valueOf("ArticleToSite"));

List<Get> gets = new ArrayList<>();
for (Cell c : t.get(get).getColumnCells("CF".getBytes(), "SiteId".getBytes())) {
    byte[] key = Bytes.add(CellUtil.cloneValue(c), ":".getBytes(), articleId);
    gets.add(new Get(key));
}
return connection.getTable(TableName.valueOf("SiteToArticle")).get(gets);
1
Lyashko Kirill 12 Дек 2019 в 14:28
Спасибо за ответ, не могли бы вы подробно описать второй вариант, пожалуйста? Было бы очень полезно, если бы вы могли предложить какой-нибудь блог, в котором был создан пользовательский вторичный индекс.
 – 
Prathamesh H
12 Дек 2019 в 13:57
Я обновил свой ответ. Вы также можете проверить hbase.apache.org/book.html#secondary.indexes для более подробной информации.
 – 
Lyashko Kirill
12 Дек 2019 в 14:31
Но уместно ли поддерживать две таблицы с 1,5 миллиардами записей? Поскольку у нас около 1000 сайтов и несколько статей на этих сайтах.
 – 
Prathamesh H
12 Дек 2019 в 14:46
Это компромисс для ускорения ваших запросов. Но если у вас всего около 1000 сайтов, я думаю, что лучше просто хранить их в каком-то хранилище памяти, а когда вам нужно получить статью по id, вы можете сгенерировать get для каждого сайта.
 – 
Lyashko Kirill
12 Дек 2019 в 15:33