After completing the four basic learning steps of Apache Cassandra, you can try the actual code.
If necessary, we suggest a brief review:
Apache Cassandra Learning Step with step (1)
Apache Cassandra Learning Step by Step (2): Core Concepts
Apache Cassandra Learning Step by Step (3): Samples ABC
Apache Cassandra Learning Step by Step (4): Data Modeling
Based on the 4th model of thinking, the next thing we have to do is to build a real project called Jtwissandra, is the so-called Java version of the Twissandra.
The goal is to use Twitter as a hypothetical object, using the simplest (or straightforward) modeling and implementation, expressed the use of Apache Cassandra as a nosql platform of the basic implementation process.
Jtwissandra Basic Coding Environment:
1. Maven to manage
2. JUnit to test
3. Java clients based on Hector client as Apache Cassandra
You can directly clone out the latest code through the following GitHub links:
Jtwissandra:https://github.com/itstarting/jtwissandra
Also welcome everyone fork or here directly to the brick--anyway, I am a novice in NoSQL, thick-skinned point does not matter:
1. First you need a hfactoryhelper to initialize and establish the Cassandra Client connection pool and the necessary objects:
Import java.io.IOException;
Import java.util.Properties;
Import Me.prettyprint.cassandra.model.ConfigurableConsistencyLevel;
Import Me.prettyprint.hector.api.Cluster;
Import Me.prettyprint.hector.api.HConsistencyLevel;
Import Me.prettyprint.hector.api.Keyspace;
Import Me.prettyprint.hector.api.factory.HFactory;
Import Org.slf4j.Logger;
Import Org.slf4j.LoggerFactory;
/**
* Helper for Cassandra initialization
*
* @author Bright_zheng
*
*/
public class Hfactoryhelper {
private static Logger Logger = Loggerfactory.getlogger (Hfactoryhelper.class);
private static Cluster Cluster;
private static Keyspace Keyspace = Initkeyspace ();
private static properties properties;
Private Hfactoryhelper () {}
public static Keyspace Getkeyspace () {
return keyspace;
}
private static Keyspace Initkeyspace () {
Properties = new properties ();
try {
Properties.load (HFactoryHelper.class.getResourceAsStream ("/config.properties"));
catch (IOException IoE) {
Ioe.printstacktrace ();
}
String cluster_name = Properties.getproperty ("Cluster.name", "Test cluster");
Logger.debug ("cluster.name={}", cluster_name);
String cluster_hosts = Properties.getproperty ("cluster.hosts", "127.0.0.1:9160");
Logger.debug ("cluster.hosts={}", cluster_hosts);
String active_keyspace = Properties.getproperty ("Keyspace", "Jtwissandra");
Logger.debug ("keyspace={}", Active_keyspace);
Cluster = Hfactory.getorcreatecluster (cluster_name, cluster_hosts);
Configurableconsistencylevel CCL = new Configurableconsistencylevel ();
Ccl.setdefaultreadconsistencylevel (Hconsistencylevel.one);
Return Hfactory.createkeyspace (
Active_keyspace,
Cluster,
CCL);
}
}
2. Establish the base class Baseservice of various business services.
Import Java.util.UUID;
Import Me.prettyprint.cassandra.serializers.LongSerializer;
Import Me.prettyprint.cassandra.serializers.StringSerializer;
Import me.prettyprint.cassandra.service.clock.MicrosecondsClockResolution;
Import Me.prettyprint.cassandra.utils.TimeUUIDUtils;
Import me.prettyprint.hector.api.ClockResolution;
Import Me.prettyprint.hector.api.Keyspace;
Import Me.prettyprint.hector.api.beans.HColumn;
Import Me.prettyprint.hector.api.factory.HFactory;
Import Org.slf4j.Logger;
Import Org.slf4j.LoggerFactory;
Import Bright.zheng.jtwissandra.HFactoryHelper;
/**
* Base service abound all business services should extend
*
* @author Bright_zheng
*
*/
public class Baseservice {
protected Logger Logger = Loggerfactory.getlogger (GetClass ());
protected static Keyspace Keyspace = Hfactoryhelper.getkeyspace ();
Protected static final String Cf_user = "USER";
Protected static final String cf_friend = "FRIEND";
Protected static final String Cf_follower = "FOLLOWER";
Protected static final String Cf_tweet = "TWEET";
Protected static final String Cf_timeline = "TIMELINE";
Protected static final Stringserializer serializer_string
= Stringserializer.get ();
Protected static final Longserializer Serializer_long
= Longserializer.get ();
protected static final int tweets_limit_default = 10;
protected static final int tweets_limit_max = 50;
Protected Hcolumn<string, string> createcolumn (string name, String value) {
Return Hfactory.createcolumn (name, value, serializer_string, serializer_string);
}
Protected Hcolumn<string, long> createcolumn (String name, Long value) {
Return Hfactory.createcolumn (name, value, serializer_string, Serializer_long);
}
Protected Hcolumn<long, string> createcolumn (Long name, String value) {
Return Hfactory.createcolumn (name, value, Serializer_long, serializer_string);
}
/**
* Ref:http://wiki.apache.org/cassandra/faq#working_with_timeuuid_in_java
*
* @return UUID
*/
Public UUID Getuuid () {
Todo:which UUID should we make throaty it's unique?
Clockresolution Clock = new Microsecondsclockresolution ();
return timeuuidutils.gettimeuuid (clock);
return Timeuuidutils.getuniquetimeuuidinmillis ();
}
Protected Long Gettimestamp (uuid uuid) {
return Uuid.timestamp ();
return Timeuuidutils.gettimefromuuid (UUID);
}
Protected Long Generatetimestamp () {
Return Gettimestamp (Getuuid ());
}
}
3. The following are the business service codes:
3.1 UserService
Package bright.zheng.jtwissandra.service;
Import Java.util.UUID;
Import Me.prettyprint.hector.api.factory.HFactory;
Import Me.prettyprint.hector.api.mutation.Mutator;
Import Bright.zheng.jtwissandra.bean.User;
/**
* User Service
*
* @author Bright_zheng
*
*/
public class UserService extends baseservice{
/**
* Sample CLI cmd:
* Set user[' 550e8400-e29b-41d4-a716-446655440000 ' [' user_name '] = ' itstarting ';
* Set user[' 550e8400-e29b-41d4-a716-446655440000 ' [' password '] = ' 111222 ';
* Set user[' 550e8400-e29b-41d4-a716-446655440000 ' [' create_timestamp '] = 1329836819890000;
*
* @param user
*/
Public String addUser (user user) {
mutator<string> Mutator = Hfactory.createmutator (
Keyspace, serializer_string);
UUID uuid = This.getuuid ();
String User_uuid = uuid.tostring ();
Long Create_timestamp = This.gettimestamp (UUID);
Logger.debug ("user_uuid={}", User_uuid);
Logger.debug ("user_name={}", User.getuser_name ());
Logger.debug ("password={}", User.getuser_password ());
Logger.debug ("create_timestamp={}", Create_timestamp);
Mutator.addinsertion (User_uuid, Cf_user,
This.createcolumn ("user_name", User.getuser_name ());
Mutator.addinsertion (User_uuid, Cf_user,
This.createcolumn ("Password", User.getuser_password ());
Mutator.addinsertion (User_uuid, Cf_user,
This.createcolumn ("Create_timestamp", Create_timestamp));
Mutator.execute ();
Return the generated UUID
return user_uuid;
}
}
3.2 Friendservice
Package bright.zheng.jtwissandra.service;
Import Me.prettyprint.hector.api.factory.HFactory;
Import Me.prettyprint.hector.api.mutation.MutationResult;
Import Me.prettyprint.hector.api.mutation.Mutator;
/**
* Friend Service
*
* @author Bright_zheng
*
*/
public class Friendservice extends baseservice{
/**
* Adding a friend super-delegates nonblank business logic:
* 1. Add the friend ' s UUID to the friend CF under my UUID
* 2. Add my uuid to the friend ' s UUID as follower
*
* Set friend[' 550e8400-e29b-41d4-a716-446655440000 ' [' 1329836819859000 ']
* = ' 550e8400-e29b-41d4-a716-446655440001;
*
* Set follower[' 550e8400-e29b-41d4-a716-446655440001 '] [' 1329836819859000 ']
* = ' 550e8400-e29b-41d4-a716-446655440000;
*
* @param me
* @param friend
*/
Public Mutationresult Followfriend (string me, string friend) {
mutator<string> Mutator = Hfactory.createmutator (
Keyspace, serializer_string);
Long timestamp = This.generatetimestamp ();
Logger.debug ("timestamp={}", timestamp);
Mutator.addinsertion (Me, Cf_friend,
This.createcolumn (timestamp, friend));
Mutator.addinsertion (friend, Cf_follower,
This.createcolumn (timestamp, ME));
return Mutator.execute ();
}
}
3.3 Timelineservice
Package bright.zheng.jtwissandra.service;
Import java.util.ArrayList;
Import Java.util.Iterator;
Import java.util.List;
Import Me.prettyprint.hector.api.beans.ColumnSlice;
Import Me.prettyprint.hector.api.beans.HColumn;
Import Me.prettyprint.hector.api.factory.HFactory;
Import Me.prettyprint.hector.api.query.QueryResult;
Import Me.prettyprint.hector.api.query.SliceQuery;
Import Bright.zheng.jtwissandra.bean.Timeline;
/**
* Timeline Service
*
* @author Bright_zheng
*
*/
public class Timelineservice extends baseservice{
/**
* Get specified user ' s Timeline
*
* @param user_uuid
* @return
*/
Public Timelinewrapper gettimeline (String user_uuid) {
Return Gettimeline (User_uuid, 0L, Tweets_limit_default);
}
/**
* Get specified user's Timeline with the start point
*
* @param user_uuid
* @param start
* @return
*/
Public Timelinewrapper gettimeline (String user_uuid, long start) {
Return Gettimeline (User_uuid, start, tweets_limit_default);
}
/**
* Get specified user's Timeline with the start point and limit
*
* @param user_uuid
* @param start
* @param limit
* @return
*/
Public Timelinewrapper gettimeline (String user_uuid, long start, int limit) {
if (start<0) start = 0;
if (limit<0) limit = Tweets_limit_default;
if (limit>tweets_limit_max) limit = Tweets_limit_max;
Slicequery<string, Long, string> slicequery =
Hfactory.createslicequery (Keyspace, serializer_string, Serializer_long, serializer_string);
Slicequery.setcolumnfamily (Cf_timeline);
Slicequery.setkey (USER_UUID);
Slicequery.setrange (Start, Long.max_value, False, limit+1);
Queryresult<columnslice<long, string>> result = Slicequery.execute ();
List<hcolumn<long, string>> list = Result.get (). GetColumns ();
Long next = 0L;
if (list==null) {
return new Timelinewrapper (null, next);
}else if (list.size () <=limit) {
return new Timelinewrapper (Converttotimeline (list), 0L);
}else{
Hcolumn<long,string> last = List.get (List.size ()-1);
Next = Last.getname (); The name is the timestamp as the "next" start
List.remove (List.size ()-1);
Return to New Timelinewrapper (Converttotimeline (list), next);
}
}
Private list<timeline> Converttotimeline (list<hcolumn<long,string>> cols) {
Iterator<hcolumn<long,string>> it = Cols.iterator ();
list<timeline> result = new arraylist<timeline> ();
while (It.hasnext ()) {
hcolumn<long,string> col = It.next ();
Result.add (New Timeline (Col.getvalue (), Col.getname ()));
}
return result;
}
public class timelinewrapper{
Private list<timeline> timelines;
Private long nexttimeline;
Public Timelinewrapper (list<timeline> timelines, long Nexttimeline) {
This.timelines = timelines;
This.nexttimeline = Nexttimeline;
}
Public long Getnexttimeline () {
return nexttimeline;
}
Public list<timeline> Gettimelines () {
return timelines;
}
}
}
3.4 Tweetservice
Package bright.zheng.jtwissandra.service;
Import java.util.ArrayList;
Import Java.util.Iterator;
Import java.util.List;
Import Java.util.UUID;
Import Me.prettyprint.hector.api.beans.ColumnSlice;
Import Me.prettyprint.hector.api.beans.HColumn;
Import Me.prettyprint.hector.api.beans.Row;
Import Me.prettyprint.hector.api.beans.Rows;
Import Me.prettyprint.hector.api.factory.HFactory;
Import Me.prettyprint.hector.api.mutation.Mutator;
Import Me.prettyprint.hector.api.query.MultigetSliceQuery;
Import Me.prettyprint.hector.api.query.QueryResult;
Import Me.prettyprint.hector.api.query.SliceQuery;
Import Bright.zheng.jtwissandra.bean.Tweet;
/**
* Tweet Service
*
* @author Bright_zheng
*
*/
public class Tweetservice extends baseservice{
/**
* Adding a tweet super-delegates following logic:
* 1. Save the tweet to CF
* 2. Add the new tweet to my TIMELINE
* 3. Add the new tweet to all my followers ' TIMELINE
*
* @param me
* @param friend
*/
public string Addtweet (string user_uuid, String tweet_content) {
mutator<string> Mutator = Hfactory.createmutator (
Keyspace, serializer_string);
The tweet UUID
UUID uuid = This.getuuid ();
String Tweet_uuid = uuid.tostring ();
Logger.debug ("tweet_uuid={}", Tweet_uuid);
The timestamp to build the timeline
Long timestamp = This.gettimestamp (UUID);
Logger.debug ("timestamp={}", timestamp);
Mutator.addinsertion (Tweet_uuid, Cf_tweet,
This.createcolumn ("User_uuid", User_uuid));
Mutator.addinsertion (Tweet_uuid, Cf_tweet,
This.createcolumn ("Tweet_content", tweet_content));
Mutator.addinsertion (User_uuid, Cf_timeline,
This.createcolumn (timestamp, tweet_uuid));
Get follower and insert the tweets to his/her TIMELINE
Slicequery<string, Long, string> slicequery =
Hfactory.createslicequery (Keyspace, serializer_string, Serializer_long, serializer_string);
Slicequery.setcolumnfamily (Cf_follower);
Slicequery.setkey (USER_UUID);
Slicequery.setrange (Long.min_value, Long.max_value, false, 500); Todo:500 followers hard code here?
Queryresult<columnslice<long, string>> result = Slicequery.execute ();
Iterator<hcolumn<long, string>> followers = Result.get (). GetColumns (). iterator ();
while (Followers.hasnext ()) {
Hcolumn<long, string> follower = Followers.next ();
String Follower_uuid = Follower.getvalue ();
Logger.debug ("Follower ' s uuid={}", Follower_uuid);
Logger.debug ("timestamp={}", Follower.getname ());
Insert the tweet to the follower ' s TIMELINE
Mutator.addinsertion (Follower_uuid, Cf_timeline,
This.createcolumn (timestamp, tweet_uuid));
}
Mutator.execute ();
Return the new generated tweet ' s UUID
return tweet_uuid;
}
/**
* Should We add this service?
*
* @param tweet_uuid
* @return
*/
Public Tweet Gettweet (String tweet_uuid) {
return null;
}
Public list<tweet> gettweets (list<string> tweet_uuids) {
Multigetslicequery<string, String, string> multigetslicesquery =
Hfactory.createmultigetslicequery (Keyspace, serializer_string, serializer_string, SERIALIZER_STRING);
Multigetslicesquery.setcolumnfamily (Cf_tweet);
Multigetslicesquery.setcolumnnames ("User_uuid", "tweet_content");
Multigetslicesquery.setkeys (Tweet_uuids);
Queryresult<rows<string, String, string>> results = Multigetslicesquery.execute ();
Return Convertrowstotweets (Results.get ());
}
Private list<tweet> convertrowstotweets (rows<string, String, string> Rows) {
list<tweet> list = new arraylist<tweet> ();
Iterator<row<string, String, string>> iterator = Rows.iterator ();
while (Iterator.hasnext ()) {
Row<string, String, string> row = Iterator.next ();
columnslice<string, String> cs = Row.getcolumnslice ();
List.add (New Tweet (Row.getkey),
Cs.getcolumnbyname ("Tweet_content"). GetValue (),
Cs.getcolumnbyname ("User_uuid"). GetValue ());
}
return list;
}
}
4. Of course, there are junit test cases:
Package Bright.zheng.jtwissandra;
Import java.util.ArrayList;
Import Java.util.Iterator;
Import java.util.List;
Import Junit.framework.Assert;
Import Org.junit.AfterClass;
Import Org.junit.BeforeClass;
Import Org.junit.Test;
Import Org.slf4j.Logger;
Import Org.slf4j.LoggerFactory;
Import Bright.zheng.jtwissandra.bean.Timeline;
Import Bright.zheng.jtwissandra.bean.Tweet;
Import Bright.zheng.jtwissandra.bean.User;
Import Bright.zheng.jtwissandra.service.FriendService;
Import Bright.zheng.jtwissandra.service.TimelineService;
Import Bright.zheng.jtwissandra.service.TimelineService.TimelineWrapper;
Import Bright.zheng.jtwissandra.service.TweetService;
Import Bright.zheng.jtwissandra.service.UserService;
/**
* Test cases for all services currently provided.
* Please drop and create schema-I-then run all cases as one round
* the ' Me ' and ' friend ' would be created each round dynamically for easier testing
*
* @author Bright_zheng
*
*/
public class servicetest{
Logger Logger = Loggerfactory.getlogger (Servicetest.class);
private static UserService Service_user = new UserService ();
private static Friendservice Service_friend = new Friendservice ();
private static Tweetservice Service_tweet = new Tweetservice ();
private static Timelineservice Service_timeline = new Timelineservice ();
private static String me;
private static String friend;
private static long nexttimeline = 0L;
@BeforeClass
public static void SetUp () {
//
}
@Test
public void AddUser () {
Logger.debug ("=====================adduser{====================");
Add User 1
me = Service_user.adduser (new USER ("itstarting", "1234"));
Logger.debug ("This round of Tesing, me={}", ME);
Assert.assertnotnull (Me);
Add User 2
Friend = Service_user.adduser (new USER ("Test1", "1234"));
Logger.debug ("This round of Tesing, friend={}", FRIEND);
Assert.assertnotnull (friend);
Logger.debug ("=====================}//adduser====================");
}
/**
* I ' m following a friend
*/
@Test
public void Followfriend () {
Logger.debug ("=====================followfriend{====================");
Service_friend.followfriend (Me, FRIEND);
Logger.debug ("=====================}//followfriend====================");
}
/**
* I ' m followed by a follower
*/
@Test
public void Followedbyfollower () {
Logger.debug ("=====================followedbyfollower{====================");
Service_friend.followfriend (FRIEND, ME);
Logger.debug ("=====================}//followedbyfollower====================");
}
/**
* I ' m twittering
*/
@Test
public void Addtweetbyme () {
Logger.debug ("=====================addtweetbyme{====================");
for (int i=0; i<100; i++) {
String Tweet_uuid = Service_tweet.addtweet (Me, "Hellow Jtwissandra-by itstarting:" + i);
Assert.assertnotnull (TWEET_UUID);
}
Logger.debug ("=====================}//addtweetbyme====================");
}
/**
* My friend is Twittering
*
*/
@Test
public void Addtweetbyfriend () {
Logger.debug ("=====================addtweetbyfriend{====================");
for (int i=0; i<100; i++) {
String tweet_uuid = Service_tweet.addtweet (friend, "Hellow Jtwissandra-by test1:" + i);
Assert.assertnotnull (TWEET_UUID);
}
Logger.debug ("=====================}//addtweetbyfriend====================");
}
/**
* Get Twitter for me
*/
@Test
public void Gettweetsbyme () {
Logger.debug ("=====================gettweetsbyme{====================");
Gettweets (me, 0);
Logger.debug ("=====================}//gettweetsbyme====================");
}
/**
* Get tweets in next Timeline (if any)
*/
@Test
public void Gettweetsbymefornexttimeline () {
Logger.debug ("=====================gettweetsbymefornexttimeline{====================");
if (nexttimeline>0l) {
Gettweets (Me, nexttimeline);
}
Logger.debug ("=====================}//gettweetsbymefornexttimeline====================");
}
/**
* Get Twitter for my friend
*/
@Test
public void Gettweetsbymyfriend () {
Logger.debug ("=====================gettweetsbymyfriend{====================");
Gettweets (friend, 0);
Logger.debug ("=====================}//gettweetsbymyfriend====================");
}
/**
*
*/
@Test
public void Gettweetsbymyfriendfornexttimeline () {
Logger.debug ("=====================gettweetsbymyfriendfornexttimeline{====================");
Gettweets (friend, Nexttimeline);
Logger.debug ("=====================}//gettweetsbymyfriendfornexttimeline====================");
}
private void Gettweets (String user_uuid, long start) {
Timelinewrapper wrappers = Service_timeline.gettimeline (User_uuid, start);
Assert.assertnotnull (wrappers);
list<timeline> list = Wrapper.gettimelines ();
list<string> tweet_uuids = new arraylist<string> ();
for (Timeline timeline:list) {
String Tweet_uuid = Timeline.gettweet_uuid ();
Logger.debug ("From timeline:tweet_uuid={}, tweet_timestamp={}",
Tweet_uuid, Timeline.gettweet_timestamp ());
Tweet_uuids.add (TWEET_UUID);
}
list<tweet> tweets = service_tweet.gettweets (tweet_uuids);
Iterator<tweet> it = Tweets.iterator ();
while (It.hasnext ()) {
Tweet = It.next ();
Logger.debug ("From tweet:tweet_uuid={}, tweet_content={}, user_uuid={}",
New Object[]{tweet.gettweet_uuid (),
Tweet.gettweet_content (),
Tweet.getuser_uuid ()
});
}
if (Wrapper.getnexttimeline () > 0L) {
Logger.debug ("The Start Timeline of next page is: {}", Wrapper.getnexttimeline ());
Nexttimeline = Wrapper.getnexttimeline ();
}else{
Logger.debug ("No next page available");
Nexttimeline = 0L;
}
}
@AfterClass
public static void shutdown () {
Cluster.getconnectionmanager (). Shutdown ();
}
}
This is a Yiguoduan test case, run all at once to cover almost any business service logic.
5. Finally, don't forget to create the necessary schema before running:
Drop Keyspace Jtwissandra;
Create Keyspace Jtwissandra
with placement_strategy = ' org.apache.cassandra.locator.SimpleStrategy '
and strategy_options = [{replication_factor:1}];
Use Jtwissandra;
Create Column Accessibility USER
With comparator = Utf8type
and Key_validation_class = Utf8type
and Default_validation_class = Utf8type
and Column_metadata = [
{column_name:user_name, Validation_class:utf8type,
Index_name:user_name_idx, Index_type:keys}
{Column_name:user_password, Validation_class:utf8type}
{Column_name:create_timestamp, Validation_class:longtype,
Index_name:create_timestamp_idx, Index_type:keys}
];
Create Column Accessibility FRIEND
With comparator = Longtype
and Key_validation_class = Utf8type
and default_validation_class = Utf8type;
Create Column Accessibility FOLLOWER
With comparator = Longtype
and Key_validation_class = Utf8type
and default_validation_class = Utf8type;
Create Column Accessibility TWEET
With comparator = Utf8type
and Key_validation_class = Utf8type
and Default_validation_class = Utf8type
and Column_metadata = [
{Column