Cassandra BoundStatement с несколькими параметрами и многораздельным запросом

После прочтения статьи "Асинхронные запросы с драйвером Java" в datastax, я пытался реализовать решение, подобное тому, что описано в разделе «Пример из практики: многораздельный запрос, также известный как «клиентский SELECT...IN».

В настоящее время у меня есть код, который выглядит примерно так:

public Future<List<ResultSet>> executeMultipleAsync(final BoundStatement statement, final Object... partitionKeys) {
    List<Future<ResultSet>> futures = Lists.newArrayListWithExpectedSize(partitionKeys.length);
    for (Object partitionKey : partitionKeys) {
      Statement bs = statement.bind(partitionKey);
      futures.add(executeWithRetry(bs));
    }
    return Futures.successfulAsList(futures);
}

Но я хотел бы улучшить это. В запросе cql, который содержит этот BoundStatement, я хотел бы иметь что-то вроде этого:

SELECT * FROM <column_family_name> WHERE <param1> = :p1_name AND param2 = :p2_name AND <partiotion_key_name> = ?;

Я бы хотел, чтобы клиенты этого метода предоставили мне BoundStatement с уже привязанными параметрами (в данном случае два параметра) и список ключей разделов. В этом случае все, что мне нужно сделать, это привязать ключи раздела и выполнить запросы. К сожалению, когда я привязываю ключ к этому оператору, я терплю ошибку - com.datastax.driver.core.exceptions.InvalidTypeException: Invalid type for value 0 of CQL type varchar, expecting class java.lang.String but class java.lang.Long provided. Проблема в том, что я пытаюсь привязать ключ к первому параметру, а не к последнему. Это строка, а не длинная.

Я могу решить эту проблему, либо указав имя параметра раздела, но тогда мне нужно будет получить имя через параметры метода, либо указав его индекс, который снова потребует дополнительного параметра метода. В любом случае, если я использую имя или индекс, я должен связать его с определенным типом. Например: bs.setLong("<key_name>", partitionKey);. По какой-то причине я не могу предоставить BoundStatement интерпретировать тип последнего параметра.

Я хотел бы избежать явной передачи имени параметра и обойти проблему типа. Есть ли что-нибудь, что можно сделать?

Спасибо!


person anatolyr    schedule 16.07.2015    source источник


Ответы (1)


Я отправил тот же вопрос в «Драйвер DataStax Java для списка рассылки пользователей Apache Cassandra» и получил ответ о том, что недостающая мне функциональность может быть добавлена ​​в следующей версии (2.2) java-драйвера datastax.

В JAVA-721 (который будет представлен в версии 2.2) мы предварительно планируем добавить следующие методы с сигнатурой в BoundStatement:

public BoundStatement setObject(int i, V v) public BoundStatement setObject(имя строки, V v)

и

Вы можете эмулировать setObject в 2.1:

void setObject(BoundStatement bs, int position, Object object,
               ProtocolVersion protocolVersion) {
     DataType type =  bs.preparedStatement().getVariables().getType(position);
     ByteBuffer buffer = type.serialize(object, protocolVersion);
     bs.setBytesUnsafe(position, buffer);
 }

Чтобы избежать передачи имени параметра, вы можете найти позицию, которая еще не привязана:

int findUnsetPosition(BoundStatement bs) {
    int size = bs.preparedStatement().getVariables().size();
    for (int i = 0; i < size; i++)
        if (!bs.isSet(i))
            return i;
    throw new IllegalArgumentException("found no unset position");
}

Однако я не рекомендую это, потому что это уродливо и непредсказуемо, если пользователь забыл связать одну из переменных, отличных от PK.

Я бы сделал так, чтобы пользователь передал обратный вызов, который устанавливает ПК:

interface PKBinder<T> {
    void bind(BoundStatement bs, T pk);
}
public <T> Future<List<ResultSet>> executeMultipleAsync(final BoundStatement statement, PKBinder<T> pkBinder, final T...

ключи разделов)

В качестве бонуса это также будет работать с составными ключами разделов.

person anatolyr    schedule 21.07.2015