[英]Issue in full table scan in cassandra
第一:我知道在Cassandra進行全面掃描並不是一個好主意,但是,目前,這就是我需要的。
當我開始尋找像這樣做的東西時,我讀到人們說不可能在卡桑德拉進行全面掃描而且他沒有做這種事情。
不滿意,我一直在尋找,直到找到這篇文章: http : //www.myhowto.org/bigdata/2013/11/04/scanning-the-entire-cassandra-column-family-with-cql/
看起來很合理,我試一試。 因為我將只執行一次全掃描,時間和性能不是問題,我編寫了查詢並將其放在一個簡單的Job中查找我想要的所有記錄。 從20億行記錄中,1000個是我預期的輸出,但是,我只有100條記錄。
我的工作:
public void run() {
Cluster cluster = getConnection();
Session session = cluster.connect("db");
LOGGER.info("Starting ...");
boolean run = true;
int print = 0;
while ( run ) {
if (maxTokenReached(actualToken)) {
LOGGER.info("Max Token Reached!");
break;
}
ResultSet resultSet = session.execute(queryBuilder(actualToken));
Iterator<Row> rows = resultSet.iterator();
if ( !rows.hasNext()){
break;
}
List<String> rowIds = new ArrayList<String>();
while (rows.hasNext()) {
Row row = rows.next();
Long leadTime = row.getLong("my_column");
if (myCondition(myCollumn)) {
String rowId = row.getString("key");
rowIds.add(rowId);
}
if (!rows.hasNext()) {
Long token = row.getLong("token(rowid)");
if (!rowIds.isEmpty()) {
LOGGER.info(String.format("Keys found! RowId's: %s ", rowIds));
}
actualToken = nextToken(token);
}
}
}
LOGGER.info("Done!");
cluster.shutdown();
}
public boolean maxTokenReached(Long actualToken){
return actualToken >= maxToken;
}
public String queryBuilder(Long nextRange) {
return String.format("select token(key), key, my_column from mytable where token(key) >= %s limit 10000;", nextRange.toString());
}
public Long nextToken(Long token){
return token + 1;
}
基本上我所做的是搜索允許的最小令牌,並逐步進行到最后一次。
我不知道,但就像工作沒有完全掃描完全掃描或我的查詢只訪問過一個節點或東西。 我不知道我做錯了什么,或者是不是真的可以進行全面掃描。
今天我有近2 TB的數據,在一個七個節點的集群中只有一個表。
有人已經處於這種情況或有一些建議嗎?
絕對有可能在Cassandra中進行全表掃描 - 事實上,它對於像Spark這樣的事情來說很常見。 然而,它通常不是“快速”,所以除非你知道你為什么這樣做,否則它是氣餒的。 對於您的實際問題:
1)如果您使用的是CQL,那么您幾乎肯定會使用Murmur3分區程序,因此您的最小標記為-9223372036854775808(最大標記為9223372036854775808)。
2)你正在使用session.execute(),它將使用一個默認的一致性,這可能不會返回你的集群中的所有結果,特別是如果你也在ONE編寫,我懷疑你可能會這樣。 將其提升為ALL,並使用預准備語句來加速CQL解析:
public void run() {
Cluster cluster = getConnection();
Session session = cluster.connect("db");
LOGGER.info("Starting ...");
actualToken = -9223372036854775808;
boolean run = true;
int print = 0;
while ( run ) {
if (maxTokenReached(actualToken)) {
LOGGER.info("Max Token Reached!");
break;
}
SimpleStatement stmt = new SimpleStatement(queryBuilder(actualToken));
stmt.setConsistencyLevel(ConsistencyLevel.ALL);
ResultSet resultSet = session.execute(stmt);
Iterator<Row> rows = resultSet.iterator();
if ( !rows.hasNext()){
break;
}
List<String> rowIds = new ArrayList<String>();
while (rows.hasNext()) {
Row row = rows.next();
Long leadTime = row.getLong("my_column");
if (myCondition(myCollumn)) {
String rowId = row.getString("key");
rowIds.add(rowId);
}
if (!rows.hasNext()) {
Long token = row.getLong("token(rowid)");
if (!rowIds.isEmpty()) {
LOGGER.info(String.format("Keys found! RowId's: %s ", rowIds));
}
actualToken = nextToken(token);
}
}
}
LOGGER.info("Done!");
cluster.shutdown();
}
public boolean maxTokenReached(Long actualToken){
return actualToken >= maxToken;
}
public String queryBuilder(Long nextRange) {
return String.format("select token(key), key, my_column from mytable where token(key) >= %s limit 10000;", nextRange.toString());
}
public Long nextToken(Long token) {
return token + 1;
}
我強烈建議使用Spark - 即使在獨立的應用程序中(即沒有集群)。 它將負責分區並逐個處理它們。 死也易於使用:
這是你需要做的常見事嗎? 還是一個案例? 我同意這不是你想要定期做的事情,但我也有一個問題,我必須閱讀ColumnFamily的所有行,我依賴Astyanax客戶端的 AllRowsReader配方 。 我看到你正在使用Datastax CQL驅動程序連接到你的集群,但如果你正在尋找的東西被證明是有用的,你可能不關心使用Astyanax庫處理問題。
在我的情況下,我曾經閱讀所有行鍵,然后我有另一個工作與我收集的鍵與ColumnFamily交互。
import com.netflix.astyanax.Keyspace;
import com.netflix.astyanax.model.ColumnFamily;
import com.netflix.astyanax.model.ConsistencyLevel;
import com.netflix.astyanax.recipes.reader.AllRowsReader;
import java.util.concurrent.CopyOnWriteArrayList;
...
private final Keyspace keyspace;
private final ColumnFamily<String, byte[]> columnFamily;
public List<String> getAllKeys() throws Exception {
final List<String> rowKeys = new CopyOnWriteArrayList<>();
new AllRowsReader.Builder<>(keyspace, columnFamily).withColumnRange(null, null, false, 0)
.withPartitioner(null) // this will use keyspace's partitioner
.withConsistencyLevel(ConsistencyLevel.CL_ONE).forEachRow(row -> {
if (row == null) {
return true;
}
String key = row.getKey();
rowKeys.add(key);
return true;
}).build().call();
return rowKeys;
}
有幾個不同的配置選項可以在多個線程和許多其他東西中運行它,比如我說我只是在我的代碼中運行了一次並且工作得非常好,如果你遇到問題試圖讓它工作,我很樂意提供幫助。
希望這可以幫助,
何塞路易斯
如果您經常需要對Cassandra表進行全表掃描,比如Spark中的分析,那么我強烈建議您考慮使用讀取優化的數據模型來存儲數據。 您可以訪問http://github.com/tuplejump/FiloDB查看Cassandra上的讀取優化設置示例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.