Запрос фрагмента кассандры довольно странные результаты

Чтение блога DataStax , Я тестировал запрос среза, даже если блог был написан с помощью Cassandra 2, а мы находимся на 3.

Итак, я определяю тестовую таблицу, как показано ниже.

CREATE TABLE foo(
  part_key TEXT,
  start_ts INT,
  end_ts INT,
  PRIMARY KEY(part_key, start_ts, end_ts)
) WITH CLUSTERING ORDER BY (start_ts ASC, end_ts ASC);

Некоторые приспособления вставлены в эту таблицу.

INSERT INTO foo(part_key, start_ts, end_ts) VALUES ('A', 1, 5);
INSERT INTO foo(part_key, start_ts, end_ts) VALUES ('A', 2, 3);
INSERT INTO foo(part_key, start_ts, end_ts) VALUES ('B', 4, 7);
INSERT INTO foo(part_key, start_ts, end_ts) VALUES ('B', 9, 13);

INSERT INTO foo(part_key, start_ts, end_ts) VALUES ('B', 1, 2);

INSERT INTO foo(part_key, start_ts, end_ts)
VALUES ('B', 9, 9999); -- 9999 = symbolic value for no end

Сначала проверяю раздел B:

> SELECT * FROM foo WHERE part_key='B';

 part_key | start_ts | end_ts
----------+----------+--------
        B |        1 |      2
        B |        4 |      7
        B |        9 |     13
        B |        9 |   9999

(4 rows)

Мы не можем выполнить "естественный" запрос SELECT * FROM foo WHERE part_key='B' AND start_ts <= 7 AND end_ts >= 7, так как это вызовет следующую ошибку.

InvalidRequest: Error from server: code=2200 [Invalid query] message="Clustering column "end_ts" cannot be restricted (preceding column "start_ts" is restricted by a non-EQ relation)"

В блоге DataStax есть запрос, как показано ниже.

SELECT * FROM numberOfRequests
    WHERE cluster = ‘cluster1’
    AND date = ‘2015-06-05’
    AND datacenter = 'US_WEST_COAST'
    AND (hour, minute) >= (12, 30) AND (hour) < (14)

Поэтому мы пробуем этот обходной путь с помощью следующего запроса среза, используя start_ts >= -9999 как всегда true и позволяя вместе указать условие неравенства для end_ts.

SELECT * FROM foo WHERE part_key='B'
AND (start_ts, end_ts) >= (-9999, 7) AND start_ts <= 7; -- -9999 = min_value

Он выполняется без предупреждения и дает результаты, указанные ниже.

 part_key | start_ts | end_ts
----------+----------+--------
        B |        1 |      2
        B |        4 |      7

(2 rows)

На этом этапе строка №1 (с start_ts = 1) не должна быть для меня, поскольку end_ts >= 7 не соответствует действительности для этой строки. Поскольку start_ts >= -9999 всегда верно, кажется, что первое условие (start_ts, end_ts) >= (-9999, 7) просто игнорируется: результаты совпадают с результатами запроса SELECT * FROM foo WHERE part_key='B' AND start_ts <= 7.

Читая пример блога, я подумал, что (по крайней мере, с C2.2), (start_ts, end_ts) >= (-9999, 7) AND start_ts <= 7 будет означать start_ts >= -9999 AND end_ts >= 7 AND start_ts <= 7, аналогично (start_ts, end_ts) = (4, 7), что означает start_ts = 4 AND end_ts = 7, как показано ниже.

SELECT * FROM foo WHERE part_key='B' AND (start_ts, end_ts) = (4, 7);

 part_key | start_ts | end_ts
----------+----------+--------
        B |        4 |      7

(1 rows)

Как на самом деле интерпретируется такое кортежное неравенство? Есть ли способ обновить его, чтобы он "работал"?


person cchantep    schedule 11.08.2017    source источник
comment
stackoverflow.com/questions/32646751/   -  person Ashraful Islam    schedule 11.08.2017
comment
Это на самом деле не отвечает или, по крайней мере, указывает на то, что результаты Кассандры несовместимы.   -  person cchantep    schedule 11.08.2017


Ответы (4)


Здесь вы выполняете сравнение по кортежу - поскольку вы объединили два столбца в кортеж, поведение сравнения несколько отличается от ожидаемого. Это правильно, это не то, чего вы ожидаете.

(start_ts, end_ts) >= (-9999, 7)

Это не означает start_ts >= -9999 && end_ts >= 7, это означает, что левая (включительно) граница - это кортеж (-9999,7). Может быть кортеж (-9998,1), который по кортежу больше (-9999,7), даже если end_ts==1 меньше 7

person Jeff Jirsa    schedule 11.08.2017

Давайте вставим еще запись

INSERT INTO foo (part_key, start_ts , end_ts ) VALUES ( 'B', 1, 7);
INSERT INTO foo (part_key, start_ts , end_ts ) VALUES ( 'B', 4, 8);
INSERT INTO foo (part_key, start_ts , end_ts ) VALUES ( 'B', 9, 7);

Теперь у нас есть данные для part_key = 'B'

cqlsh:test> SELECT * FROM foo WHERE part_key='B' ;

 part_key | start_ts | end_ts
----------+----------+--------
        B |        1 |      2
        B |        1 |      7
        B |        4 |      7
        B |        4 |      8
        B |        9 |      7
        B |        9 |     13
        B |        9 |   9999

Теперь давайте запросим эти данные:

cqlsh:test> SELECT * FROM foo WHERE part_key='B' AND (start_ts, end_ts) >= (1, 4) AND (start_ts, end_ts) <= (9, 7);

 part_key | start_ts | end_ts
----------+----------+--------
        B |        1 |      7
        B |        4 |      7
        B |        4 |      8
        B |        9 |      7

Похоже, результат неверный. Но это не так. Наше понимание неверно.

Cassandra будет хранить ваши данные, отсортированные по составному полю (start_ts, end_ts), сначала сортируя по start_ts, затем для каждого start_ts sort end_ts. Когда мы запрашиваем с (start_ts, end_ts) >= (1, 4) AND (start_ts, end_ts) <= (9, 7). Кассандра рассматривает (start_ts, end_ts) как одно составное поле, и его значение находится в диапазоне от (1, 4) до (9,7).

 part_key | start_ts | end_ts
----------+----------+--------
        B |        1 |      2
-------------------------------> start range
        B |        1 |      7
        B |        4 |      7
        B |        4 |      8
        B |        9 |      7
-------------------------------> end range       
        B |        9 |     13
        B |        9 |   9999

Надеюсь ты понимаешь.

person Ashraful Islam    schedule 11.08.2017
comment
Спасибо, это подтверждает, что Кассандра не может запрашивать по дате / диапазону - person cchantep; 11.08.2017
comment
Да, вам нужно отфильтровать его со стороны клиента - person Ashraful Islam; 11.08.2017
comment
Это единственный способ сказать, что Кассандра может найти только совпадающие данные :-) - person cchantep; 11.08.2017
comment
Ничто в этом поведении не указывает на то, что кассандра не может выполнять запросы по дате / диапазону. Вы используете предложение WHERE по кортежу. - person Jeff Jirsa; 11.08.2017

Один из возможных подходов - использовать фильтрацию для второго столбца. К сожалению, фильтрация по столбцам кластеризации поддерживается только с версии 3.6. Поэтому, если ваша версия меньше этой, но является версией 3.0.x, вы можете решить свою проблему, преобразовав второй столбец кластеризации в обычный. В этом случае следующий запрос даст вам ожидаемые результаты:

SELECT * FROM foo WHERE part_key='B' AND start_ts = 7 ALLOW FILTERING

Я не знаю ваших данных и их количества, поэтому фильтрация может быть не лучшим вариантом.

Другой вариант - изменить вашу модель данных. Есть разные способы моделирования вещей, чтобы получить запрос, который эффективно удовлетворяет ваши потребности.

person Benjamin Lerer    schedule 29.08.2017

Все дело в ORDER кортежей, а не в VALUE отдельных столбцов. Проще говоря, речь идет не о сравнении значений, а о сравнении порядка кортежей. Как только Cassandra упорядочивает кортежи на основе вашего порядка кластеризации, она просто сравнивает порядок кортежей. Например, в разделе B данного набора: (start_ts, end_ts)> = (1, 1) AND (start_ts, end_ts) ‹= (7, 7)

Первая часть этого логического И: (start_ts, end_ts)> = (1, 1) будет включать все кортежи ниже этого (1,1) кортежа: (1,2), (4,7), (9,13) , (9,9999)

Вторая часть этого логического И: (start_ts, end_ts) ‹= (7, 7) будет включать все кортежи выше этого (7,7) кортежа: (1,2), (4,7)

Из-за такой конструкции всегда будет необходимость в дальнейших проверках кода. Например, если в вашей таблице есть столбцы с датой начала и окончания и вы сгруппировали ее с помощью StartDate ASC и EndDate ASC; и вы ищете все строки между диапазоном FromDate-ToDate, вам всегда придется дополнительно фильтровать строки в коде. Для этого в предложении where у вас будет: (StartDate, EndDate)> = (FromDate, FromDate) AND (StartDate, EndDate) ‹= (ToDate, ToDate).

Это НЕ будет эквивалентно условию SQL: StartDate> = FromDate AND EndDate ‹= ToDate

Надеюсь это поможет.

person Shubham Dwivedi    schedule 22.02.2018