问题
I have a scheme as follows:
- TimeStamp
- Device ID
- Device Name
- Device Owner
- Device location
I have created this column family using CQL and defined the primary key as (TimeStamp,Device ID, Device Name)
. Through a serializable object that has fields for DeviceID, name and a field name (which stores either Device Owner
or Device Location
). I have inserted some records using Astyanax.
As per my understanding, the columns for a row are created by combining Device ID
, Device Name
and field name as column name and the value to be the value for that particular field.
Thus for a particular timestamp and device, the column names would be in the pattern (Device ID:Device Name: ...)
.
So I believe we can use these 2 fields as prefix to obtain all the entries for a particular time-device combination.
I am using the following query to obtain the results:
RowSliceQuery<String, ApBaseData> query = adu.keyspace
.prepareQuery(columnFamily)
.getKeySlice(timeStamp)
.withColumnRange(new RangeBuilder()
.setStart(deviceID+deviceName+"_\u00000")
.setEnd(deviceID+deviceName+"_\uffff")
.setLimit(batch_size)
.build());
But on executing the above query I get the following Exception:
BadRequestException: [host=localhost(127.0.0.1):9160, latency=6(6), attempts=1]InvalidRequestException(why:Not enough bytes to read value of component 0)
@abhi The data I can have in this column family is as follows:
stime | devName | devId | Owner | Location
1361260800 | dev:01:02 | 1 | 1234 | 1
1361260800 | dev:02:03 | 2 | 34 | 2
1361260800 | dev:05:06 | 1 | 12 | 1
1361260800 | dev:03:02 | 2 | 56 | 3
The java seriazable java class that I am using for this is:
public class BaseData implements Serializable {
private static final long serialVersionUID = 1L;
@Component(ordinal = 0)
private String devName;
@Component(ordinal = 1)
private int devID;
@Component(ordinal = 2)
private String field;
}
Following the structure of the above class I can see columns in the column family as : Columne Name: dev\:01\:02:1:location Column Value: 00000001
FYI using astyanax 1.56.31
回答1:
You could use PlayOrm for cassandra (which I hear the latest is working on mongodb as well now). Using that you could create an entity and add the @NoSqlPartitionByField annotation to the beginOfMonthTimestamp AND the deviceId column and in addition have the timestamp column. That then allows you queries into partitions like so
PARTITIONS s('time', :partitionId) select s from TABLE as s where s.deviceName='mike'
This is ok only if you are sure your partition will not be more than millions. You can have infinite partitions though. So basically, you might use beginOfMonth or beginOfWeek depending on how fast stuff is coming into the system. There is more info at
http://buffalosw.com/wiki/playorm-documentation/
回答2:
Two things here,
1. You are using ":" in your device id which is also used by Cassandra for composite columns. So avoid using that if you can.
2. Your columnname says "dev\:01\:02:1:location" which is devicename+deviceid+location as per your test data. However you are giving deviceID+deviceName+"_\u00000" in your query??
回答3:
To overcome this problem, I changed the way I was storing data in the table. Instead of using a composite primary key, I changed the schema so as to have only single primary key and dynamic columns. So, now I have primary key on stime and my column names are constructed dynamically explicitly by my insertion code. For eg. "dev\:01\:02:1:location" the same way they were before but this has completely eliminated the need of a serialized object. This has solved my problem as of now. Lets see what problems it poses later.
来源:https://stackoverflow.com/questions/15744575/querying-columns-with-prefix-not-working-using-astyanax