Writing to Google Cloud Storage from PubSub using Cloud Dataflow using DoFn - google-cloud-storage

I am trying write Google PubSub messages to Google Cloud Storage using Google Cloud Dataflow. I know that TextIO/AvroIO do not support streaming pipelines. However, I read in [1] that it is possible to write to GCS in a streaming pipeline from a ParDo/DoFn in a comment by the author. I constructed a pipeline by following their article as closely as I could.
I was aiming for this behaviour:
Messages written out in a batches of up to 100 to objects in GCS (one per window pane) under a path that corresponds to the time the message was published in dataflow-requests/[isodate-time]/[paneIndex].
I get different results:
There is only a single pane in every hourly window. I therefore only get one file in every hourly 'bucket' (it's really an object path in GCS). Reducing MAX_EVENTS_IN_FILE to 10 made no difference, still only one pane/file.
There is only a single message in every GCS object that is written out
The pipeline occasionally raises a CRC error when writing to GCS.
How do I fix these problems and get the behaviour I'm expecting?
Sample log output:
21:30:06.977 writing pane 0 to blob dataflow-requests/2016-04-08T20:59:59.999Z/0
21:30:06.977 writing pane 0 to blob dataflow-requests/2016-04-08T20:59:59.999Z/0
21:30:07.773 sucessfully write pane 0 to blob dataflow-requests/2016-04-08T20:59:59.999Z/0
21:30:07.846 sucessfully write pane 0 to blob dataflow-requests/2016-04-08T20:59:59.999Z/0
21:30:07.847 writing pane 0 to blob dataflow-requests/2016-04-08T20:59:59.999Z/0
Here is my code:
package com.example.dataflow;
import com.google.cloud.dataflow.sdk.Pipeline;
import com.google.cloud.dataflow.sdk.io.PubsubIO;
import com.google.cloud.dataflow.sdk.options.DataflowPipelineOptions;
import com.google.cloud.dataflow.sdk.options.PipelineOptions;
import com.google.cloud.dataflow.sdk.options.PipelineOptionsFactory;
import com.google.cloud.dataflow.sdk.transforms.DoFn;
import com.google.cloud.dataflow.sdk.transforms.ParDo;
import com.google.cloud.dataflow.sdk.transforms.windowing.*;
import com.google.cloud.dataflow.sdk.values.PCollection;
import com.google.gcloud.storage.BlobId;
import com.google.gcloud.storage.BlobInfo;
import com.google.gcloud.storage.Storage;
import com.google.gcloud.storage.StorageOptions;
import org.joda.time.Duration;
import org.joda.time.format.ISODateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
public class PubSubGcsSSCCEPipepline {
private static final Logger LOG = LoggerFactory.getLogger(PubSubGcsSSCCEPipepline.class);
public static final String BUCKET_PATH = "dataflow-requests";
public static final String BUCKET_NAME = "myBucketName";
public static final Duration ONE_DAY = Duration.standardDays(1);
public static final Duration ONE_HOUR = Duration.standardHours(1);
public static final Duration TEN_SECONDS = Duration.standardSeconds(10);
public static final int MAX_EVENTS_IN_FILE = 100;
public static final String PUBSUB_SUBSCRIPTION = "projects/myProjectId/subscriptions/requests-dataflow";
private static class DoGCSWrite extends DoFn<String, Void>
implements DoFn.RequiresWindowAccess {
public transient Storage storage;
{ init(); }
public void init() { storage = StorageOptions.defaultInstance().service(); }
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
init();
}
#Override
public void processElement(ProcessContext c) throws Exception {
String isoDate = ISODateTimeFormat.dateTime().print(c.window().maxTimestamp());
String blobName = String.format("%s/%s/%s", BUCKET_PATH, isoDate, c.pane().getIndex());
BlobId blobId = BlobId.of(BUCKET_NAME, blobName);
LOG.info("writing pane {} to blob {}", c.pane().getIndex(), blobName);
storage.create(BlobInfo.builder(blobId).contentType("text/plain").build(), c.element().getBytes());
LOG.info("sucessfully write pane {} to blob {}", c.pane().getIndex(), blobName);
}
}
public static void main(String[] args) {
PipelineOptions options = PipelineOptionsFactory.fromArgs(args).withValidation().create();
options.as(DataflowPipelineOptions.class).setStreaming(true);
Pipeline p = Pipeline.create(options);
PubsubIO.Read.Bound<String> readFromPubsub = PubsubIO.Read.named("ReadFromPubsub")
.subscription(PUBSUB_SUBSCRIPTION);
PCollection<String> streamData = p.apply(readFromPubsub);
PCollection<String> windows = streamData.apply(Window.<String>into(FixedWindows.of(ONE_HOUR))
.withAllowedLateness(ONE_DAY)
.triggering(AfterWatermark.pastEndOfWindow()
.withEarlyFirings(AfterPane.elementCountAtLeast(MAX_EVENTS_IN_FILE))
.withLateFirings(AfterFirst.of(AfterPane.elementCountAtLeast(MAX_EVENTS_IN_FILE),
AfterProcessingTime.pastFirstElementInPane()
.plusDelayOf(TEN_SECONDS))))
.discardingFiredPanes());
windows.apply(ParDo.of(new DoGCSWrite()));
p.run();
}
}
[1] https://labs.spotify.com/2016/03/10/spotifys-event-delivery-the-road-to-the-cloud-part-iii/
Thanks to Sam McVeety for the solution. Here is the corrected code for anyone reading:
package com.example.dataflow;
import com.google.cloud.dataflow.sdk.Pipeline;
import com.google.cloud.dataflow.sdk.io.PubsubIO;
import com.google.cloud.dataflow.sdk.options.DataflowPipelineOptions;
import com.google.cloud.dataflow.sdk.options.PipelineOptions;
import com.google.cloud.dataflow.sdk.options.PipelineOptionsFactory;
import com.google.cloud.dataflow.sdk.transforms.*;
import com.google.cloud.dataflow.sdk.transforms.windowing.*;
import com.google.cloud.dataflow.sdk.values.KV;
import com.google.cloud.dataflow.sdk.values.PCollection;
import com.google.gcloud.WriteChannel;
import com.google.gcloud.storage.BlobId;
import com.google.gcloud.storage.BlobInfo;
import com.google.gcloud.storage.Storage;
import com.google.gcloud.storage.StorageOptions;
import org.joda.time.Duration;
import org.joda.time.format.ISODateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Iterator;
public class PubSubGcsSSCCEPipepline {
private static final Logger LOG = LoggerFactory.getLogger(PubSubGcsSSCCEPipepline.class);
public static final String BUCKET_PATH = "dataflow-requests";
public static final String BUCKET_NAME = "myBucketName";
public static final Duration ONE_DAY = Duration.standardDays(1);
public static final Duration ONE_HOUR = Duration.standardHours(1);
public static final Duration TEN_SECONDS = Duration.standardSeconds(10);
public static final int MAX_EVENTS_IN_FILE = 100;
public static final String PUBSUB_SUBSCRIPTION = "projects/myProjectId/subscriptions/requests-dataflow";
private static class DoGCSWrite extends DoFn<Iterable<String>, Void>
implements DoFn.RequiresWindowAccess {
public transient Storage storage;
{ init(); }
public void init() { storage = StorageOptions.defaultInstance().service(); }
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
init();
}
#Override
public void processElement(ProcessContext c) throws Exception {
String isoDate = ISODateTimeFormat.dateTime().print(c.window().maxTimestamp());
long paneIndex = c.pane().getIndex();
String blobName = String.format("%s/%s/%s", BUCKET_PATH, isoDate, paneIndex);
BlobId blobId = BlobId.of(BUCKET_NAME, blobName);
LOG.info("writing pane {} to blob {}", paneIndex, blobName);
WriteChannel writer = storage.writer(BlobInfo.builder(blobId).contentType("text/plain").build());
LOG.info("blob stream opened for pane {} to blob {} ", paneIndex, blobName);
int i=0;
for (Iterator<String> it = c.element().iterator(); it.hasNext();) {
i++;
writer.write(ByteBuffer.wrap(it.next().getBytes()));
LOG.info("wrote {} elements to blob {}", i, blobName);
}
writer.close();
LOG.info("sucessfully write pane {} to blob {}", paneIndex, blobName);
}
}
public static void main(String[] args) {
PipelineOptions options = PipelineOptionsFactory.fromArgs(args).withValidation().create();
options.as(DataflowPipelineOptions.class).setStreaming(true);
Pipeline p = Pipeline.create(options);
PubsubIO.Read.Bound<String> readFromPubsub = PubsubIO.Read.named("ReadFromPubsub")
.subscription(PUBSUB_SUBSCRIPTION);
PCollection<String> streamData = p.apply(readFromPubsub);
PCollection<KV<String, String>> keyedStream =
streamData.apply(WithKeys.of(new SerializableFunction<String, String>() {
public String apply(String s) { return "constant"; } }));
PCollection<KV<String, Iterable<String>>> keyedWindows = keyedStream
.apply(Window.<KV<String, String>>into(FixedWindows.of(ONE_HOUR))
.withAllowedLateness(ONE_DAY)
.triggering(AfterWatermark.pastEndOfWindow()
.withEarlyFirings(AfterPane.elementCountAtLeast(MAX_EVENTS_IN_FILE))
.withLateFirings(AfterFirst.of(AfterPane.elementCountAtLeast(MAX_EVENTS_IN_FILE),
AfterProcessingTime.pastFirstElementInPane()
.plusDelayOf(TEN_SECONDS))))
.discardingFiredPanes())
.apply(GroupByKey.create());
PCollection<Iterable<String>> windows = keyedWindows
.apply(Values.<Iterable<String>>create());
windows.apply(ParDo.of(new DoGCSWrite()));
p.run();
}
}

There's a gotcha here, which is that you'll need a GroupByKey in order for the panes to be aggregated appropriate. The Spotify example references this as "Materialization of panes is done in “Aggregate Events” transform which is nothing else than a GroupByKey transform", but it's a subtle point. You'll need to provide a key in order to do this, and in your case, it appears a constant value will work.
PCollection<String> streamData = p.apply(readFromPubsub);
PCollection<KV<String, String>> keyedStream =
streamData.apply(WithKeys.of(new SerializableFunction<String, String>() {
public Integer apply(String s) { return "constant"; } }));
At this point, you can apply your windowing function, and then a final GroupByKey to get the desired behavior:
PCollection<String, Iterable<String>> keyedWindows = keyedStream.apply(...)
.apply(GroupByKey.create());
PCollection<Iterable<String>> windows = keyedWindows
.apply(Values.<Iterable<String>>create());
Now the elements in processElement will be Iterable<String>, with size 100 or more.
We've filed https://issues.apache.org/jira/browse/BEAM-184 to make this behavior clearer.

As of Beam 2.0, TextIO/AvroIO do support writing unbounded collections - see documentation, in particular, you have to specify withWindowedWrites().

Related

Flink Streaming Event time Window

I am running a simple example to test window based on EventTime. I am able to generate output with processing time but when i using EventTime, no output is coming . Please help me to understand what i am doing wrong.
i am creating a SlidingWindow of size 10 seconds which slides every 5 seconds and at the end of the window, the system will emit the number of messages that were received during that time.
input :
a,1513695853 (generated at 13th second, received at 13th second)
a,1513695853 (generated at 13th second, received at 13th second)
a,1513695856 (generated at 16th second, received at 19th second)
a,1513695859 (generated at 13th second, received at 19th second)
2nd field represent timestamp of event, representing 13th,13th,16th,19th second of a minute.
if i am using Processing Time window :
Output :
(a,1)
(a,3)
(a,2)
But when i am using Event Time than no output is printing. Please help me to understand what is going wrong.
package org.apache.flink.window.training;
import java.io.InputStream;
import java.util.Properties;
import org.apache.flink.api.common.functions.FoldFunction;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.AssignerWithPunctuatedWatermarks;
import org.apache.flink.streaming.api.watermark.Watermark;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer010;
import org.apache.flink.streaming.util.serialization.SimpleStringSchema;
import com.fasterxml.jackson.databind.ObjectMapper;
public class SocketStream {
private static Properties properties = new Properties();
public static void main(String args[]) throws Exception {
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
InputStream inputStream =
SocketStream.class.getClassLoader().getResourceAsStream("local-kafka-server.properties");
properties.load(inputStream);
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
FlinkKafkaConsumer010<String> consumer =
new FlinkKafkaConsumer010<>("test-topic", new SimpleStringSchema(), properties);
DataStream<Element> socketStockStream =
env.addSource(consumer).map(new MapFunction<String, Element>() {
#Override
public Element map(String value) throws Exception {
String split[] = value.split(",");
Element element = new Element(split[0], Long.parseLong(split[1]));
return element;
}
}).assignTimestampsAndWatermarks(new TimestampExtractor());
socketStockStream.map(new MapFunction<Element, Tuple2<String, Integer>>() {
#Override
public Tuple2<String, Integer> map(Element value) throws Exception {
return new Tuple2<String, Integer>(value.getId(), 1);
}
}).keyBy(0).timeWindow(Time.seconds(10), Time.seconds(5))
.sum(1).
print();
env.execute();
}
public static class TimestampExtractor implements AssignerWithPunctuatedWatermarks<Element> {
private static final long serialVersionUID = 1L;
#Override
public long extractTimestamp(Element element, long previousElementTimestamp) {
return element.getTimestamp();
}
#Override
public Watermark checkAndGetNextWatermark(Element lastElement, long extractedTimestamp) {
// TODO Auto-generated method stub
return null;
}
}
}
Event-time processing requires properly generated timestamps and watermarks.
The TimestampExtractor in your code does not generate watermark but returns always null.

(Eclipse) Syntax Highlighting Plugin, odd issues with getting started on highlighting/validation

I'm making a syntax highlighting plugin for my company. I'm not making a new editor, I am using an eclipse template that uses the Extensions for generic editor.
Disclaimer: I've had a lot of trouble getting XText to work consistently on 3 different machines due to versioning issues, missing files etc. so that's out of the question
org.eclipse.ui.genericeditor.presentationReconcilers
org.eclipse.ui.genericeditor.contentTypes
org.eclipse.ui.genericeditor.hoverProviders
org.eclipse.ui.genericeditor.contentAssistProcessors
org.eclipse.ui.editors
org.eclipse.core.filebuffers.documentSetup
I'm using I'm having some odd issues. Before I get started:
The plugin is detected in Help > About Eclipse > Installation Details > Plugins
Other sample plugins run using the same method i used to run this plugin
Problems:
I'm getting the following error message when placing any content in
the file except <?xml version='1.0'>:
"Content is not allowed in Prolog"
The keywords seem to be highlighted in Blue. As you can see in my
source code, they should be highlighted in red.
Click here to view what my runtime Eclipe editor looks like
when i'm trying to test my syntax rules.
Below are my classes source code.
I'm wondering:
why my keywords are being recognized in syntax coloring but are
invalid commands with that "prolog" error above
Why the prolog errors above are occurring
Why it's validating the file not to my specification or to a different specification
Point me in the right direction
Hope you can help.
Thanks :).
Reconciler Class:
package myplugin;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.presentation.PresentationReconciler;
import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
public class MyReconciler extends PresentationReconciler {
public MyReconciler() {
// TODO this is logic for .project file to color tags in blue. Replace with your language logic!
MyScanner scanner = new MyScanner(new SyntaxColorProvider());
DefaultDamagerRepairer dr= new DefaultDamagerRepairer(scanner);
this.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);
this.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);
}
}
Scanner class:
package myplugin;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.text.TextAttribute;
import org.eclipse.jface.text.rules.BufferedRuleBasedScanner;
import org.eclipse.jface.text.rules.EndOfLineRule;
import org.eclipse.jface.text.rules.IRule;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.IWordDetector;
import org.eclipse.jface.text.rules.MultiLineRule;
import org.eclipse.jface.text.rules.PatternRule;
import org.eclipse.jface.text.rules.SingleLineRule;
import org.eclipse.jface.text.rules.Token;
import org.eclipse.jface.text.rules.WhitespaceRule;
import org.eclipse.jface.text.rules.WordRule;
public class MyScanner extends BufferedRuleBasedScanner
{
private static String[] misc = {
true",
"false",
"unsigned",
"jump",
"read",
"write",
};
// Tokens
private final IToken KEYWORD_TOKEN;
private List<IRule> basicRules;
public MyScanner(SyntaxColorProvider colorProvider)
{
super(5000);
// CREATE TOKENS
KEYWORD_TOKEN = new Token(new TextAttribute(colorProvider.getColor(SyntaxColorProvider.KEYWORD)));
// CREATE RULES
List rules = new ArrayList<IRule>();
// Add rule for strings and character constants.
rules.add(new SingleLineRule("\"", "\"", STRING_TOKEN, '\\'));
rules.add(new SingleLineRule("'", "'", STRING_TOKEN, '\\'));
// Add word rule for keywords, types, and constants.
WordRule wordRule = new WordRule(new WordDetector(), OTHER_TOKEN);
// Single-line comments
rules.add(new EndOfLineRule("//", STRING_TOKEN));
// Multi-line comments
rules.add(new MultiLineRule("/$", "$/", COMMENT_TOKEN));
// KEYWORDS
for (String misc : misc)
{
wordRule.addWord(misc, KEYWORD_TOKEN);
}
rules.add(wordRule);
IRule[] result= new IRule[rules.size()];
rules.toArray(result);
setRules(result);
}
}
ValidatorDocumentSetupParticipant:
package myplugin;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.eclipse.core.filebuffers.IDocumentSetupParticipant;
import org.eclipse.core.filebuffers.IDocumentSetupParticipantExtension;
import org.eclipse.core.filebuffers.LocationKind;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.xml.sax.InputSource;
import org.xml.sax.SAXParseException;
public class ValidatorDocumentSetupParticipant implements IDocumentSetupParticipant, IDocumentSetupParticipantExtension {
private final class DocumentValidator implements IDocumentListener {
private final IFile file;
private IMarker marker;
private DocumentValidator(IFile file) {
this.file = file;
}
#Override
public void documentChanged(DocumentEvent event) {
if (this.marker != null) {
try {
this.marker.delete();
} catch (CoreException e) {
e.printStackTrace();
}
this.marker = null;
}
try (StringReader reader = new StringReader(event.getDocument().get());) {
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
documentBuilder.parse(new InputSource(reader));
} catch (Exception ex) {
try {
this.marker = file.createMarker(IMarker.PROBLEM);
this.marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
this.marker.setAttribute(IMarker.MESSAGE, ex.getMessage());
if (ex instanceof SAXParseException) {
SAXParseException saxParseException = (SAXParseException)ex;
int lineNumber = saxParseException.getLineNumber();
int offset = event.getDocument().getLineInformation(lineNumber - 1).getOffset() + saxParseException.getColumnNumber() - 1;
this.marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
this.marker.setAttribute(IMarker.CHAR_START, offset);
this.marker.setAttribute(IMarker.CHAR_END, offset + 1);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void documentAboutToBeChanged(DocumentEvent event) {
}
}
#Override
public void setup(IDocument document) {
}
#Override
public void setup(IDocument document, IPath location, LocationKind locationKind) {
if (locationKind == LocationKind.IFILE) {
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(location);
document.addDocumentListener(new DocumentValidator(file));
}
WordDetector Class:
package myplugin;
import org.eclipse.jface.text.rules.IWordDetector;
public class WordDetector implements IWordDetector
{
public boolean isWordPart(char character) {
return Character.isJavaIdentifierPart(character);
}
public boolean isWordStart(char character) {
return Character.isJavaIdentifierStart(character);
}
}
SyntaxColorProvider Class:
package myplugin;
import java.util.HashMap;
public class SyntaxColorProvider
{
public static final RGB RED = new RGB(200, 0, 0);
public static final RGB GREEN = new RGB(0, 200, 0);
public static final RGB BLUE = new RGB(0, 0, 200);
public static final RGB COMMENT = new RGB(128, 128, 128);
public static final RGB KEYWORD = new RGB(255, 0, 0);
public static final RGB TYPE = new RGB(0, 0, 128);
public static final RGB STRING = new RGB(0, 128, 0);
public static final RGB DEFAULT = new RGB(0, 0, 0);
protected Map fColorTable = new HashMap(10);
/**
* Release all of the color resources held onto by the receiver.
*/
public void dispose()
{
Iterator e = fColorTable.values().iterator();
while (e.hasNext())
((Color) e.next()).dispose();
}
/**
* Return the Color that is stored in the Color table as rgb.
*/
public Color getColor(RGB rgb)
{
Color color = (Color) fColorTable.get(rgb);
if (color == null)
{
color = new Color(Display.getCurrent(), rgb);
fColorTable.put(rgb, color);
}
return color;
}
This looks like the sample editor with some changes - and
documentBuilder.parse(new InputSource(reader));
would be parsing XML, perhaps. It detects improper XML because the prolog is missing. Remove that line from the code, or implement something that flags up and marks issues similarly.
Ok so I've struggled with the same probelm the function that makes this problem is in this line: documentBuilder.parse(new InputSource(reader));, Im in the middle of trying to figure out a text parser by myself.

Showing contact from the contact loader Manager

I am showing the contact list from the contact table but not able to get the phone number using the same on RecyclerView.My code is -
package com.oodles.oodlesapprtc;
import android.annotation.SuppressLint;
import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import java.util.ArrayList;
/**
* Created by ankita on 13/4/17.
*/
public class LoginUserActivity extends AppCompatActivity {
public static final int CONTACT_LOADER_ID = 78;
RecyclerView loginUserRecycler;
ArrayList<ContactBeans> contactBeanses;
String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME +
" COLLATE LOCALIZED ASC";
private static final String[] PROJECTION2 = {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY, ContactsContract.Contacts.PHOTO_URI,ContactsContract.Contacts.HAS_PHONE_NUMBER
};
private static final String[] PROJECTION3 = {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY, ContactsContract.Contacts.PHOTO_URI, ContactsContract.Contacts.LOOKUP_KEY
};
private static final String[] PROJECTION = {
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY, ContactsContract.CommonDataKinds.Phone.NUMBER
};
// private static final String[] PROJECTION1 = {
// ContactsContract.Data.CONTACT_ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY,
// ContactsContract.CommonDataKinds.Phone.NUMBER
// };
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login_user_activity);
initViews();
}
private void initViews() {
getLoaderManager().initLoader(0, null, contactLoaderManager);
initRecycler();
}
private void initRecycler() {
loginUserRecycler = (RecyclerView) findViewById(R.id.loginUserRecycler);
loginUserRecycler.setLayoutManager(new LinearLayoutManager(this));
loginUserRecycler.setItemAnimator(new DefaultItemAnimator());
}
LoaderManager.LoaderCallbacks<Cursor> contactLoaderManager = new LoaderManager.LoaderCallbacks<Cursor>() {
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// String[] projectionFields = new String[]{ContactsContract.Contacts._ID,
// ContactsContract.Contacts.DISPLAY_NAME,ContactsContract.PhoneLookup.NORMALIZED_NUMBER,
// ContactsContract.Contacts.PHOTO_URI};
// Construct the loader
// Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
// ContactsContract.Contacts.CONTENT_URI
// Uri lookupUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
// Uri.encode(phoneNumber));
CursorLoader cursorLoader = new CursorLoader(LoginUserActivity.this,
ContactsContract.Contacts.CONTENT_URI, // URI
PROJECTION2, // projection fields
null, // the selection criteria
null, // the selection args
sortOrder // the sort order
);
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
loginUserRecycler.setAdapter(new CursorRecyclerAdapter(LoginUserActivity.this, data));
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
};
}
My Adapter is -
package com.oodles.oodlesapprtc;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by ankita on 13/4/17.
*/
public class CursorRecyclerAdapter extends RecyclerView.Adapter<ContactViewHolder> {
private Cursor mCursor;
private final int mNameColIdx,
mIdColIdx;
int phoneNumber;
int hasPhoneNumber;
private Context mContext;
public CursorRecyclerAdapter(Context context, Cursor cursor) {
mCursor = cursor;
this.mContext = context;
mNameColIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY);
mIdColIdx = cursor.getColumnIndex(ContactsContract.Contacts._ID);
hasPhoneNumber = cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER);
}
#Override
public ContactViewHolder onCreateViewHolder(ViewGroup parent, int pos) {
View listItemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.contact_row, parent, false);
return new ContactViewHolder(listItemView);
}
#Override
public void onBindViewHolder(ContactViewHolder contactViewHolder, int pos) {
mCursor.moveToPosition(pos);
String contactName = mCursor.getString(mNameColIdx);
long contactId = mCursor.getLong(mIdColIdx);
Contact c = new Contact();
Log.e("ddhdhdhhdhdhdhd",hasPhoneNumber+"");
c.name = contactName;
c.number = getPhoneNumberFromContactId(contactId);
c.profilePic = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);
getPhoneNumberFromContactId(contactId);
contactViewHolder.bind(c);
}
private String getPhoneNumberFromContactId(long contactId) {
String contactNumber = "8874675724";
return contactNumber;
}
#Override
public int getItemCount() {
return mCursor.getCount();
}
}
How can I get the phone number for the same i am getting a cursorindexoutofbound exception and has phone number value as 3 but it can be only 0 or 1 why it is 3 i don't understand this.
Can Anyone please explain this to me also please explain how the contact fetch works
You have a few issues in the code:
You're querying on the Contacts table, but sorting using a CommonDataKinds.Phone table field, that's not good, you can sort using Contacts.DISPLAY_NAME_PRIMARY instead.
cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER) gives you a column index, not the value of the field, that's why you're getting 3 (it's the 4rd field defined in PROJECTION2), change hasPhoneNumber to mHasPhoneNumberIdx to avoid confusion.
add hasPhoneNumber = mCursor.getInt(mHasPhoneNumberIdx); to your onBindViewHolder method, to get the actual value.
Running a long command like a real implementation of getPhoneNumberFromContactId within onBindViewHolder is really bad... you should change your main query so you do two big queries, one for all contacts, one for all phones, and then use some HashMap to get a phone using a contact-id.

Updating the color of rows of a TableView consumes too much CPU

I am making an application that receives alerts.
An alert can have 4 possible states:
Unresolved_New_0
Unresolved_New_1
Unresolved_Old
Resolved
When an alert is received, it is in Unresolved_New_0 state. For 10 seconds, every 0.5s the state changes from Unresolved_New_0 to Unresolved_New_1 and vice-versa. Depending on state I, set a different background color to the table row (so that it flashes, for 10s).
When the 10s pass, the alert transitions to Unresolved_Old state. This causes its color to stop changing.
To implement this, I have a ScheduledThreadPoolExecutor that I use to submit an implementation of Runnable that for some time executes a runnable using Platform.runLater.
static class FxTask extends Runnable {
/**
*
* #param runnableDuring Runnable to be run while the task is active (run on the JavaFX application thread).
* #param runnableAfter Runnable to be run after the given duration is elapsed (run on the JavaFX application thread).
* #param duration Duration to run this task for.
* #param unit Time unit.
*/
public static FxTask create(final Runnable runnableDuring, final Runnable runnableAfter, final long duration, final TimeUnit unit) {
return new FxTask(runnableDuring, runnableAfter, duration, unit);
}
#Override
public void run() {
if (System.nanoTime() - mTimeStarted >= mTimeUnit.toNanos(mDuration) )
{
cancel();
Platform.runLater(mRunnableAfter);
}
else
Platform.runLater(mRunnableDuring);
}
private FxTask(final Runnable during, final Runnable after, final long duration, final TimeUnit unit) {
mRunnableDuring = during;
mRunnableAfter = after;
mDuration = duration;
mTimeUnit = unit;
mTimeStarted = System.nanoTime();
}
private final Runnable mRunnableDuring;
private final Runnable mRunnableAfter;
private final long mDuration;
private final TimeUnit mTimeUnit;
private final long mTimeStarted;
}
And I schedule Alerts using that Runnable as follows:
final Alert alert = new Alert(...);
scheduler.scheduleAtFixedRate(FxTask.create(
() -> {
switch (alert.alertStateProperty().get()) {
case UNRESOLVED_NEW_0:
alert.alertStateProperty().set(Alert.State.UNRESOLVED_NEW_1);
refreshTable(mAlertsTable);
break;
case UNRESOLVED_NEW_1:
alert.alertStateProperty().set(Alert.State.UNRESOLVED_NEW_0);
refreshTable(mAlertsTable);
break;
}
},
() -> { // This is run at the end
if (equalsAny(alert.alertStateProperty().get(), Alert.State.UNRESOLVED_NEW_0, SpreadAlert.State.UNRESOLVED_NEW_1)) {
alert.alertStateProperty().set(Alert.State.UNRESOLVED_OLD);
refreshTable(mAlertsTable);
}
},
10, TimeUnit.SECONDS), 0, 500, TimeUnit.MILLISECONDS
);
Note: alertStateProperty() is not shown on the TableView (it is not bound to any of its columns).
So in order to force JavaFx to redraw, I have to use refreshTable(), which unfortunately redraws the whole table (?).
public static <T> void refreshTable(final TableView<T> table) {
table.getColumns().get(0).setVisible(false);
table.getColumns().get(0).setVisible(true);
}
The problem is that even if I create a small number of Alerts at the same time, CPU usage goes very high: from 20% to 84% sometimes, averaging at about 40%. When the 10s pass for all alerts, CPU consumptions returns to 0%. If I comment out refreshTable(), CPU stays near 0%, which indicates that it is the problem.
Why is so much CPU being used? (I have 8 cores by the way).
Is there another way to redraw just a single row without redrawing the whole table?
I even tried a 'hacky' method -- changing all values of the Alerts and then resetting them back to cause JavaFx to detect the change and redraw, but CPU was again at the same levels.
Probably the most efficient way to change the color of a table row is to use a table row factory, have the table row it creates observe the appropriate property, and update one or more CSS PseudoClass states as appropriate. Then just define the colors in an external css file.
Here's a standalone version of the application you described. I just used a Timeline to perform the "flashing new alerts", which is less code; but use the executor as you have it if you prefer. The key idea here is the table row factory, and the pseudoclass state it manipulates by observing the property. On my system, if I fill the entire table with new (flashing) rows, the CPU doesn't exceed about 35% (percentage of one core), which seems perfectly acceptable.
Note that PseudoClass was introduced in Java 8. In earlier versions of JavaFX you can achieve the same by manipulating the style classes instead, though you have to be careful not to duplicate any style classes as they are stored as a List. Anecdotally, the pseudoclass approach is more efficient.
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener.Change;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.stage.Stage;
import javafx.util.Duration;
public class AlertTableDemo extends Application {
#Override
public void start(Stage primaryStage) {
TableView<Alert> table = new TableView<>();
table.getColumns().add(createColumn("Name", Alert::nameProperty));
table.getColumns().add(createColumn("Value", Alert::valueProperty));
TableColumn<Alert, Alert> resolveCol =
createColumn("Resolve", ReadOnlyObjectWrapper<Alert>::new);
resolveCol.setCellFactory(this::createResolveCell);
table.getColumns().add(resolveCol);
// just need a wrapper really, don't need the atomicity...
AtomicInteger alertCount = new AtomicInteger();
Random rng = new Random();
Button newAlertButton = new Button("New Alert");
newAlertButton.setOnAction( event ->
table.getItems().add(new Alert("Alert "+alertCount.incrementAndGet(),
rng.nextInt(20)+1)));
// set psuedo-classes on table rows depending on alert state:
table.setRowFactory(tView -> {
TableRow<Alert> row = new TableRow<>();
ChangeListener<Alert.State> listener = (obs, oldState, newState) ->
updateTableRowPseudoClassState(row, row.getItem().getState());
row.itemProperty().addListener((obs, oldAlert, newAlert) -> {
if (oldAlert != null) {
oldAlert.stateProperty().removeListener(listener);
}
if (newAlert == null) {
clearTableRowPseudoClassState(row);
} else {
updateTableRowPseudoClassState(row, row.getItem().getState());
newAlert.stateProperty().addListener(listener);
}
});
return row ;
});
// flash new alerts:
table.getItems().addListener((Change<? extends Alert> change) -> {
while (change.next()) {
if (change.wasAdded()) {
List<? extends Alert> newAlerts =
new ArrayList<>(change.getAddedSubList());
flashAlerts(newAlerts);
}
}
});
HBox controls = new HBox(5, newAlertButton);
controls.setPadding(new Insets(10));
controls.setAlignment(Pos.CENTER);
BorderPane root = new BorderPane(table, null, null, controls, null);
Scene scene = new Scene(root, 800, 600);
scene.getStylesheets().add(
getClass().getResource("alert-table.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
private void flashAlerts(List<? extends Alert> newAlerts) {
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(0.5),
event -> {
for (Alert newAlert : newAlerts) {
if (newAlert.getState()==Alert.State.UNRESOLVED_NEW_0) {
newAlert.setState(Alert.State.UNRESOLVED_NEW_1);
} else if (newAlert.getState() == Alert.State.UNRESOLVED_NEW_1){
newAlert.setState(Alert.State.UNRESOLVED_NEW_0);
}
}
}));
timeline.setOnFinished(event -> {
for (Alert newAlert : newAlerts) {
if (newAlert.getState() != Alert.State.RESOLVED) {
newAlert.setState(Alert.State.UNRESOLVED_OLD);
}
}
});
timeline.setCycleCount(20);
timeline.play();
}
private void clearTableRowPseudoClassState(Node node) {
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("unresolved-new"), false);
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("unresolved-new-alt"), false);
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("unresolved-old"), false);
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("resolved"), false);
}
private void updateTableRowPseudoClassState(Node node, Alert.State state) {
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("unresolved-new"),
state==Alert.State.UNRESOLVED_NEW_0);
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("unresolved-new-alt"),
state==Alert.State.UNRESOLVED_NEW_1);
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("unresolved-old"),
state==Alert.State.UNRESOLVED_OLD);
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("resolved"),
state==Alert.State.RESOLVED);
}
private TableCell<Alert, Alert> createResolveCell(TableColumn<Alert, Alert> col) {
TableCell<Alert, Alert> cell = new TableCell<>();
Button resolveButton = new Button("Resolve");
resolveButton.setOnAction(event ->
cell.getItem().setState(Alert.State.RESOLVED));
cell.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
cell.setAlignment(Pos.CENTER);
cell.graphicProperty().bind(
Bindings.when(cell.emptyProperty())
.then((Node)null)
.otherwise(resolveButton));
return cell ;
}
private <S, T> TableColumn<S, T> createColumn(String title,
Function<S, ObservableValue<T>> propertyMapper) {
TableColumn<S,T> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> propertyMapper.apply(cellData.getValue()));
col.setMinWidth(Region.USE_PREF_SIZE);
col.setPrefWidth(150);
return col ;
}
public static class Alert {
public enum State {
UNRESOLVED_NEW_0, UNRESOLVED_NEW_1, UNRESOLVED_OLD, RESOLVED
}
private final ObjectProperty<State> state = new SimpleObjectProperty<>();
private final StringProperty name = new SimpleStringProperty();
private final IntegerProperty value = new SimpleIntegerProperty();
public final ObjectProperty<State> stateProperty() {
return this.state;
}
public final AlertTableDemo.Alert.State getState() {
return this.stateProperty().get();
}
public final void setState(final AlertTableDemo.Alert.State state) {
this.stateProperty().set(state);
}
public final StringProperty nameProperty() {
return this.name;
}
public final java.lang.String getName() {
return this.nameProperty().get();
}
public final void setName(final java.lang.String name) {
this.nameProperty().set(name);
}
public final IntegerProperty valueProperty() {
return this.value;
}
public final int getValue() {
return this.valueProperty().get();
}
public final void setValue(final int value) {
this.valueProperty().set(value);
}
public Alert(String name, int value) {
setName(name);
setValue(value);
setState(State.UNRESOLVED_NEW_0);
}
}
public static void main(String[] args) {
launch(args);
}
}
alert-table.css:
.table-row-cell:resolved {
-fx-background: green ;
}
.table-row-cell:unresolved-old {
-fx-background: red ;
}
.table-row-cell:unresolved-new {
-fx-background: blue ;
}
.table-row-cell:unresolved-new-alt {
-fx-background: yellow ;
}

How to solve the chainmapper is not applicable for the arguments error while doing job chaining in Mapreduce?

I'm using Hadoop 1.2.1, eclipse juno. I'm trying to chaining three map task in a single Mapreduce job. while writing Mapreduce code in eclipse, I'm getting error like chainmapper is not applicable for the arguments and also I cant set inputpath. Following are my mapreduce code,
package org.myorg;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.util.StringTokenizer;
import javax.security.auth.login.Configuration;
import org.apache.hadoop.classification.InterfaceAudience.Private;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapred.FileOutputFormat;
import org.apache.hadoop.mapred.JobClient;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.MapReduceBase;
import org.apache.hadoop.mapred.MapRunnable;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reducer;
import org.apache.hadoop.mapred.Reporter;
import org.apache.hadoop.mapred.TextInputFormat;
import org.apache.hadoop.mapred.TextOutputFormat;
import org.apache.hadoop.mapred.lib.ChainMapper;
import org.apache.hadoop.mapred.lib.ChainReducer;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.net.StaticMapping;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
public class Recommand extends Configured implements Tool {
public static class IdIndexMapper extends MapReduceBase implements Mapper<LongWritable, Text, Text, Text>{
public void map(LongWritable key, Text val, OutputCollector<Text, Text> output,Reporter reporter)throws IOException{
String[] ids;
String ln=val.toString();
ids=ln.split("\t");
output.collect(new Text(ids[0]),new Text(ids[1]));
}
}
public static class FtrMapper extends MapReduceBase implements Mapper<Text, Text, Text, Text>{
public void map(Text key, Text val, OutputCollector<Text, Text>output, Reporter reporter) throws IOException{
String[] str;
String lne=val.toString();
while(lne.contains("M1024")){
str=lne.split(",");
String[] str1=new String[str.length];
for(int i=0;i<str.length;i++){
if(str[i]=="M1024"){ //hre need to give id which we need to split;
continue;
}
str1[i]=str[i];
output.collect(key,new Text(str1[i]));
// System.out.println("str1 out:"+str[i]);
}
}
}
}
public static class CntMapper extends MapReduceBase implements Mapper<Text, Text, Text, IntWritable>{
private final static IntWritable one=new IntWritable(1);
private Text word=new Text();
public void map(Text key, Text val, OutputCollector<Text, IntWritable>output, Reporter reporter)throws IOException{
String line = val.toString();
StringTokenizer tokenizer = new StringTokenizer(line);
while (tokenizer.hasMoreTokens()) {
word.set(tokenizer.nextToken());
output.collect(word, one);
}
}
}
public static class Reduce extends MapReduceBase implements Reducer<Text, IntWritable, Text, IntWritable>{
public void reduce(Text key, Iterable<IntWritable>values, OutputCollector<Text, IntWritable>output, Reporter reporter)throws IOException{
int sum=0;
for(IntWritable val:values){
sum+=val.get();
}
output.collect(key,new IntWritable(sum));
}
}
static int printUsage() {
System.out.println("recommand ");
ToolRunner.printGenericCommandUsage(System.out);
return -1;
}
public int run(String[] args) throws Exception {
JobConf conf = new JobConf(getConf(), Recommand.class);
conf.setJobName("wordcount");
if (args.length != 2) {
System.out.println("ERROR: Wrong number of parameters: " +
args.length + " instead of 2.");
return printUsage();
}
FileInputFormat.setInputPaths(conf, args[0]);
FileOutputFormat.setOutputPath(conf, new Path(args[1]));
conf.setInputFormat(TextInputFormat.class);
conf.setOutputFormat(TextOutputFormat.class);
JobConf mapAConf = new JobConf(false);
ChainMapper.addMapper(conf, IdIndexMapper.class, LongWritable.class, Text.class, Text.class, Text.class, true, mapAConf);
JobConf mapBConf = new JobConf(false);
ChainMapper.addMapper(conf, FtrMapper.class, Text.class, Text.class, Text.class, Text.class, true, mapBConf);
JobConf mapCConf = new JobConf(false);
ChainMapper.addMapper(conf, CntMapper.class, Text.class, Text.class, Text.class, IntWritable.class, true, mapBConf);
JobConf reduceConf = new JobConf(false);
ChainReducer.setReducer(conf, Reduce.class, Text.class, IntWritable.class, Text.class, IntWritable.class, true, reduceConf);
JobClient.runJob(conf);
return 0;
}
public static void main(String[] args) throws Exception {
int res = ToolRunner.run(new org.apache.hadoop.conf.Configuration(), Recommand(), args);
System.exit(res);
}
}
Can anyone help me to solve this problem please?
Make sure of the following to avoid this error
Both classes extend the Mapper class.
The ChainMapper class being used is from the correct API, whichever is applicable to your code.
org.apache.hadoop.mapreduce.lib.chain.ChainMapper or import org.apache.hadoop.mapred.lib.ChainMapper