diff --git a/CHANGES.txt b/CHANGES.txt
index f3f16e84c8..31fd319234 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -24,6 +24,7 @@
* Improve PerRowSecondaryIndex performance (CASSANDRA-6876)
* Extend triggers to support CAS updates (CASSANDRA-6882)
* Static columns with IF NOT EXISTS don't always work as expected (CASSANDRA-6873)
+ * Add CqlRecordReader to take advantage of native CQL pagination (CASSANDRA-6311)
Merged from 1.2:
* Add UNLOGGED, COUNTER options to BATCH documentation (CASSANDRA-6816)
* add extra SSL cipher suites (CASSANDRA-6613)
diff --git a/build.xml b/build.xml
index 464dece9bd..a15415b531 100644
--- a/build.xml
+++ b/build.xml
@@ -380,6 +380,7 @@
+
@@ -410,7 +411,7 @@
-
+
@@ -473,6 +474,7 @@
+
diff --git a/examples/hadoop_cql3_word_count/bin/word_count b/examples/hadoop_cql3_word_count/bin/word_count
index a0c5aa02f1..974a39aed3 100644
--- a/examples/hadoop_cql3_word_count/bin/word_count
+++ b/examples/hadoop_cql3_word_count/bin/word_count
@@ -56,6 +56,7 @@ if [ "x$JAVA" = "x" ]; then
fi
OUTPUT_REDUCER=cassandra
+INPUT_MAPPER=native
#echo $CLASSPATH
-$JAVA -Xmx1G -ea -cp $CLASSPATH WordCount output_reducer=$OUTPUT_REDUCER
+$JAVA -Xmx1G -ea -cp $CLASSPATH WordCount output_reducer=$OUTPUT_REDUCER input_mapper=$INPUT_MAPPER
diff --git a/examples/hadoop_cql3_word_count/bin/word_count_counters b/examples/hadoop_cql3_word_count/bin/word_count_counters
index 779347743f..0b69b407c8 100644
--- a/examples/hadoop_cql3_word_count/bin/word_count_counters
+++ b/examples/hadoop_cql3_word_count/bin/word_count_counters
@@ -54,5 +54,7 @@ if [ "x$JAVA" = "x" ]; then
exit 1
fi
+INPUT_MAPPER=native
+
#echo $CLASSPATH
-$JAVA -Xmx1G -ea -cp $CLASSPATH WordCountCounters
+$JAVA -Xmx1G -ea -cp $CLASSPATH WordCountCounters input_mapper=$INPUT_MAPPER
diff --git a/examples/hadoop_cql3_word_count/src/WordCount.java b/examples/hadoop_cql3_word_count/src/WordCount.java
index bc81a5322d..519a98f1d4 100644
--- a/examples/hadoop_cql3_word_count/src/WordCount.java
+++ b/examples/hadoop_cql3_word_count/src/WordCount.java
@@ -27,6 +27,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.cassandra.hadoop.cql3.CqlPagingInputFormat;
+import org.apache.cassandra.hadoop.cql3.CqlInputFormat;
import org.apache.cassandra.hadoop.ConfigHelper;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.hadoop.conf.Configuration;
@@ -37,10 +38,11 @@ import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
+import org.apache.hadoop.mapreduce.Mapper.Context;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
-
+import com.datastax.driver.core.Row;
import java.nio.charset.CharacterCodingException;
/**
@@ -60,7 +62,7 @@ import java.nio.charset.CharacterCodingException;
public class WordCount extends Configured implements Tool
{
private static final Logger logger = LoggerFactory.getLogger(WordCount.class);
-
+ static final String INPUT_MAPPER_VAR = "input_mapper";
static final String KEYSPACE = "cql3_worldcount";
static final String COLUMN_FAMILY = "inputs";
@@ -68,7 +70,6 @@ public class WordCount extends Configured implements Tool
static final String OUTPUT_COLUMN_FAMILY = "output_words";
private static final String OUTPUT_PATH_PREFIX = "/tmp/word_count";
-
private static final String PRIMARY_KEY = "row_key";
public static void main(String[] args) throws Exception
@@ -108,6 +109,30 @@ public class WordCount extends Configured implements Tool
}
}
+ public static class NativeTokenizerMapper extends Mapper
+ {
+ private final static IntWritable one = new IntWritable(1);
+ private Text word = new Text();
+ private ByteBuffer sourceColumn;
+
+ protected void setup(org.apache.hadoop.mapreduce.Mapper.Context context)
+ throws IOException, InterruptedException
+ {
+ }
+
+ public void map(Long key, Row row, Context context) throws IOException, InterruptedException
+ {
+ String value = row.getString("line");
+ logger.debug("read {}:{}={} from {}", new Object[] {key, "line", value, context.getInputSplit()});
+ StringTokenizer itr = new StringTokenizer(value);
+ while (itr.hasMoreTokens())
+ {
+ word.set(itr.nextToken());
+ context.write(word, one);
+ }
+ }
+ }
+
public static class ReducerToFilesystem extends Reducer
{
public void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException
@@ -149,17 +174,41 @@ public class WordCount extends Configured implements Tool
public int run(String[] args) throws Exception
{
String outputReducerType = "filesystem";
- if (args != null && args[0].startsWith(OUTPUT_REDUCER_VAR))
+ String inputMapperType = "native";
+ String outputReducer = null;
+ String inputMapper = null;
+
+ if (args != null)
{
- String[] s = args[0].split("=");
+ if(args[0].startsWith(OUTPUT_REDUCER_VAR))
+ outputReducer = args[0];
+ if(args[0].startsWith(INPUT_MAPPER_VAR))
+ inputMapper = args[0];
+
+ if (args.length == 2)
+ {
+ if(args[1].startsWith(OUTPUT_REDUCER_VAR))
+ outputReducer = args[1];
+ if(args[1].startsWith(INPUT_MAPPER_VAR))
+ inputMapper = args[1];
+ }
+ }
+
+ if (outputReducer != null)
+ {
+ String[] s = outputReducer.split("=");
if (s != null && s.length == 2)
outputReducerType = s[1];
}
logger.info("output reducer type: " + outputReducerType);
-
+ if (inputMapper != null)
+ {
+ String[] s = inputMapper.split("=");
+ if (s != null && s.length == 2)
+ inputMapperType = s[1];
+ }
Job job = new Job(getConf(), "wordcount");
job.setJarByClass(WordCount.class);
- job.setMapperClass(TokenizerMapper.class);
if (outputReducerType.equalsIgnoreCase("filesystem"))
{
@@ -189,9 +238,19 @@ public class WordCount extends Configured implements Tool
ConfigHelper.setOutputPartitioner(job.getConfiguration(), "Murmur3Partitioner");
}
- job.setInputFormatClass(CqlPagingInputFormat.class);
+ if (inputMapperType.equalsIgnoreCase("native"))
+ {
+ job.setMapperClass(NativeTokenizerMapper.class);
+ job.setInputFormatClass(CqlInputFormat.class);
+ CqlConfigHelper.setInputCql(job.getConfiguration(), "select * from " + COLUMN_FAMILY + " where token(id) > ? and token(id) <= ? allow filtering");
+ }
+ else
+ {
+ job.setMapperClass(TokenizerMapper.class);
+ job.setInputFormatClass(CqlPagingInputFormat.class);
+ ConfigHelper.setInputRpcPort(job.getConfiguration(), "9160");
+ }
- ConfigHelper.setInputRpcPort(job.getConfiguration(), "9160");
ConfigHelper.setInputInitialAddress(job.getConfiguration(), "localhost");
ConfigHelper.setInputColumnFamily(job.getConfiguration(), KEYSPACE, COLUMN_FAMILY);
ConfigHelper.setInputPartitioner(job.getConfiguration(), "Murmur3Partitioner");
diff --git a/examples/hadoop_cql3_word_count/src/WordCountCounters.java b/examples/hadoop_cql3_word_count/src/WordCountCounters.java
index 542a473cf4..74de9abf81 100644
--- a/examples/hadoop_cql3_word_count/src/WordCountCounters.java
+++ b/examples/hadoop_cql3_word_count/src/WordCountCounters.java
@@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory;
import org.apache.cassandra.hadoop.cql3.CqlConfigHelper;
import org.apache.cassandra.hadoop.cql3.CqlPagingInputFormat;
+import org.apache.cassandra.hadoop.cql3.CqlInputFormat;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
@@ -37,7 +38,7 @@ import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
-
+import com.datastax.driver.core.Row;
import org.apache.cassandra.hadoop.ConfigHelper;
import org.apache.cassandra.utils.ByteBufferUtil;
@@ -51,6 +52,7 @@ public class WordCountCounters extends Configured implements Tool
{
private static final Logger logger = LoggerFactory.getLogger(WordCountCounters.class);
+ static final String INPUT_MAPPER_VAR = "input_mapper";
static final String COUNTER_COLUMN_FAMILY = "input_words_count";
private static final String OUTPUT_PATH_PREFIX = "/tmp/word_count_counters";
@@ -61,6 +63,24 @@ public class WordCountCounters extends Configured implements Tool
System.exit(0);
}
+ public static class SumNativeMapper extends Mapper
+ {
+ long sum = -1;
+ public void map(Long key, Row row, Context context) throws IOException, InterruptedException
+ {
+ if (sum < 0)
+ sum = 0;
+
+ logger.debug("read " + key + ":count_num from " + context.getInputSplit());
+ sum += Long.valueOf(row.getString("count_num"));
+ }
+
+ protected void cleanup(Context context) throws IOException, InterruptedException {
+ if (sum > 0)
+ context.write(new Text("total_count"), new LongWritable(sum));
+ }
+ }
+
public static class SumMapper extends Mapper