I want three values, they are aggValueInLastHour aggValueInLastDay aggValueInLastThreeDay.
I've tried like below.
But I don't want to wait, means that I'm not prefer to use sliding window to do aggregation.(3 day window must wait three days' data, this is unbearable for our system.)
How can I get last 3 day aggregation value when first event come?
Thanks for any advice in advance!
If you want to get more frequent updates you can use QueryableState, polling the state at a rate that suits your use case.
You can make use of the ContinuousEventTimeTrigger, which will cause your window to fire on a shorter time period than the the full window, allowing you to see the intermediate state. You can optionally wrap that in a PurgingTrigger if the downstream consumers of your sink are expecting each output to be a partial aggregation (rather than the full current state) and sums them up.
I've tried CEP.
code:
AfterMatchSkipStrategy strategy = AfterMatchSkipStrategy.skipShortOnes();
Pattern<RiskEvent, ?> loginPattern = Pattern.<RiskEvent>begin("start", strategy)
.where(eventTypeCondition)
.timesOrMore(1)
.greedy()
.within(Time.hours(1));
KeyedStream<RiskEvent, String> keyedStream = dataStream.keyBy(new KeySelector<RiskEvent, String>() {
#Override
public String getKey(RiskEvent riskEvent) throws Exception {
// key by user for aggregation
return riskEvent.getEventType() + riskEvent.getDeviceFp();
}
});
PatternStream<RiskEvent> eventPatternStream = CEP.pattern(keyedStream, loginPattern);
eventPatternStream.select(new PatternSelectFunction<RiskEvent, RiskResult>() {
#Override
public RiskResult select(Map<String, List<RiskEvent>> map) throws Exception {
List<RiskEvent> list = map.get("start");
ArrayList<Long> times = new ArrayList<>();
for (RiskEvent riskEvent : list) {
times.add(riskEvent.getEventTime());
}
Long min = Collections.min(times);
Long max = Collections.max(times);
Set<String> accountList = list.stream().map(RiskEvent::getUserName).collect(Collectors.toSet());
logger.info("时间范围:" + new Date(min) + " --- " + new Date(max) + " 事件:" + list.get(0).getEventType() + ", 设备指纹:" + list.get(0).getDeviceFp() + ", 关联账户:" + accountList.toString());
return null;
}
});
maybe you notice that, the skip strategy skipShortOnes is a customized strategy.
Show you my modification in CEP lib.
add strategy in Enum.
public enum SkipStrategy{
NO_SKIP,
SKIP_PAST_LAST_EVENT,
SKIP_TO_FIRST,
SKIP_TO_LAST,
SKIP_SHORT_ONES
}
add access method in AfterMatchSkipStrategy.java
public static AfterMatchSkipStrategy skipShortOnes() {
return new AfterMatchSkipStrategy(SkipStrategy.SKIP_SHORT_ONES);
}
add strategy actions in discardComputationStatesAccordingToStrategy method at NFA.java.
case SKIP_SHORT_ONES:
int i = 0;
List>> tempResult = new ArrayList<>(matchedResult);
for (Map> resultMap : tempResult) {
if (i++ == 0) {
continue;
}
matchedResult.remove(resultMap);
}
break;
Related
I need to compare the previous session to averages from different sessions for the same user. I'm using MapState to keep the previous session, but somehow the mapstate never contains any previous keys, so every session is new. here's my code:
SessionIdentificationProcessFunction (this is a function that gather all the events that belongs to the same session.
static SingleOutputStreamOperator<SessionEvent> sessionUser(KeyedStream<Event, String> stream) {
return stream.window(EventTimeSessionWindows.withGap(Time.minutes(PropertyFileReader.getGAP_SECTION())))
.allowedLateness(Time.minutes(PropertyFileReader.getLATENCY_ALLOWED()))
.process(new SessionIdentificationProcessFunction<Event, SessionEvent, String, TimeWindow>() {
#Override
public void open(Configuration parameters) {
/*state configured to live just one day to avoid garbage accumulation*/
StateTtlConfig ttlConfig = StateTtlConfig
.newBuilder(org.apache.flink.api.common.time.Time.days(1))
.cleanupFullSnapshot()
.build();
MapStateDescriptor<String, SessionEvent> map_descriptor = new MapStateDescriptor<>("prevMapUserSession", String.class, SessionEvent.class);
map_descriptor.enableTimeToLive(ttlConfig);
previous_user_sessions_state = getRuntimeContext().getMapState(map_descriptor);
}
#Override
public SessionEvent generateSessionRecord(String s, Context context, Iterable<Event> elements) {
Comparator<Event> sortFunc = (o1, o2) -> ((o1.timestamp.before(o2.timestamp)) ? 0 : 1);
Event start = StreamSupport.stream(elements.spliterator(), false).max(sortFunc).orElse(new Event());
Event end = StreamSupport.stream(elements.spliterator(), false).max(sortFunc).orElse(new Event());
SessionEvent session_user = (end.timestamp.equals(Timestamp.from(Instant.EPOCH))) ? new SessionEvent(start) : new SessionEvent(end);
session_user.sessionEvents = StreamSupport.stream(elements.spliterator(), false).count();
session_user.sessionDuration = sd;
try {
if (previous_user_sessions_state.contains(s)) {
SessionEvent previous = previous_user_sessions_state.get(s);
/*Update values of the session with the values of the previous which never exist and delete the previous session in the map to create a new entry with the new values updated*/
previous_user_sessions_state.remove(s);
} else {
/*always get here and create a new session*/
}
previous_user_sessions_state.put(s, session_user);
} catch (Exception e) {
e.printStackTrace();
}
return session_user;
}
})
.name("User Sessions");
}
Without seeing how SessionIdentificationProcessFunction is implemented, I'm not sure exactly what's going wrong, but Flink's session windows are rather special, so it's not terribly surprising that this isn't working. Part of the problem is that any given session window has a very short lifetime before it is merged with another session window. (As each new event arrives it is initially assigned to its own session window, after which the set of all current session windows is processed and any possible merges are performed (based on the session gap).)
What I can recommend is rather than using getRuntimeContext().getMapState(), use context.globalState().getMapState() instead (where context is the ProcessWindowFunction.Context passed to the process() method of a ProcessWindowFunction). This globalState is a KeyedStateStore meant for precisely this purpose -- keeping keyed state that is global/shared among all window instances for that key.
I'm new to this. After scrolling my ListView, items in "same position" as items I selected before get auto selected. (Same position I mean position in the screen not in the database.) I had this prob before, because I was selecting items by their indexes of ListView in OnItemClickListener. However i face this prob again although I'm doing it right way I think.
When I click on item in ListView, I get its unique ID and based on that I change SELECTED value of this item (of this row in the database) to 0 or 1 (depending on this if it was clicked or not). After that I switch backgrnd color to grey (or back to white). This is handled in CursorAdapter which distinguishes SELECTED property.
Here's my code.
OnCreate in MainActivity.kt
val dbHelper = DBHelper(this)
val db = dbHelper.writableDatabase
val myCursor = db.rawQuery("SELECT * FROM ${ContractClass.FeedReaderContract.TABLE_NAME}", null)
val myAdapter = CursorAdapter(this, myCursor)
myListView.adapter = myAdapter
myListView.setOnItemClickListener { _, view, _, _ ->
val text = view.txtName.text
val select = "${ContractClass.FeedReaderContract.COLUMN_NAME_ENWORD} MATCH ?"
val selectCursor = db.query(
ContractClass.FeedReaderContract.TABLE_NAME, // The table to query
null, // The array of columns to return (pass null to get all)
select, // The columns for the WHERE clause
arrayOf("$text"), // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
null // The sort order
)
with(selectCursor) {
while (moveToNext()) {
val itemSel = getInt(getColumnIndexOrThrow(ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED))
if (itemSel == 1){
val values = ContentValues().apply {
put(ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED, 0)
}
val count = db.update(
ContractClass.FeedReaderContract.TABLE_NAME, values, select, arrayOf("$text"))
}else{
val values = ContentValues().apply {
put(ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED, 1)
}
val count = db.update(
ContractClass.FeedReaderContract.TABLE_NAME, values, select, arrayOf("$text"))
}
}
}
}
CursorAdapter.kt
class CursorAdapter(context: Context, cursor: Cursor) : CursorAdapter(context, cursor, 0) {
// The newView method is used to inflate a new view and return it,
// you don't bind any data to the view at this point.
override fun newView(context: Context, cursor: Cursor, parent: ViewGroup): View {
if (cursor.getInt(cursor.getColumnIndexOrThrow(ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED)) == 0){
return LayoutInflater.from(context).inflate(R.layout.row_list_row, parent, false)
}else{
return LayoutInflater.from(context).inflate(R.layout.user_list_row_selected, parent, false)
}
}
// The bindView method is used to bind all data to a given view
// such as setting the text on a TextView.
override fun bindView(view: View, context: Context, cursor: Cursor) {
// Find fields to populate in inflated template
val tvBody = view.findViewById<View>(R.id.txtName) as TextView
val tvPriority = view.findViewById<View>(R.id.txtComment) as TextView
val tvPriority2 = view.findViewById<View>(R.id.txtThird) as TextView
val tvPriority3 = view.findViewById<View>(R.id.txtThi) as TextView
// Extract properties from cursor
val body = cursor.getString(cursor.getColumnIndexOrThrow(ContractClass.FeedReaderContract.COLUMN_NAME_ENWORD))
val priority = cursor.getString(cursor.getColumnIndexOrThrow(ContractClass.FeedReaderContract.COLUMN_NAME_DEFN))
val priority2 = cursor.getInt(cursor.getColumnIndexOrThrow(ContractClass.FeedReaderContract._id))
val priority3 = cursor.getInt(cursor.getColumnIndexOrThrow(ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED))
// Populate fields with extracted properties
tvBody.text = body
tvPriority.text = priority.toString()
tvPriority2.text = priority2.toString()
tvPriority3.text = priority3.toString()
}
}
Database Table Create
private val SQL_CREATE_ENTRIES =
"CREATE VIRTUAL TABLE ${ContractClass.FeedReaderContract.TABLE_NAME} USING fts4(" +
"${ContractClass.FeedReaderContract._id}," +
"${ContractClass.FeedReaderContract.COLUMN_NAME_ENWORD} TEXT," +
"${ContractClass.FeedReaderContract.COLUMN_NAME_DEFN} TEXT," +
"${ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED} INTEGER)"
I found similar post here: List view with simple cursor adapter items checked are un-checked during scroll
but I think, they suggest what I've already done.
Thanks for any help.
You don't appear to be changing the ListView's Cursor after you have made changes to/updated the underlying data.
Try, after making changes to the underlying data, updating the ListView's Cursor by
re-querying the data and then
using the Adapter's swapCursor(myCursor) (or the notiftDatasetChanged() method)
Here's an equivalent of your App but in Java rather than Kotlin (not having any luck converting as I hardly ever use Kotlin).
This I believe does what you want. That is,
If you select an unselected row then all rows that contain the enword are selected and greyed out and the selected column value is set to 1.
If you select a selected (grey) row then those rows that contain the enword are de-selected and are change to white with the selected column value being changed back to 0
Note that rather than create an FTS table I've mimicked the FTS and used LIKE instead of MATCH.
Are toggled if they are selected the background is grey else white. e.g. initially it is :-
If cat is clicked (2nd row) then all other cat rows are also toggled and greyed as per :-
and so on.
The Code
MainActivity (the file I had issues converting)
public class MainActivity extends AppCompatActivity {
DBHelper dbhelper;
ListView myListView;
MyCursorAdapter myAdapter;
Cursor mCursor;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myListView = this.findViewById(R.id.myListView);
dbhelper = new DBHelper(this);
addSomeTestingData();
manageListView();
}
private void manageListView() {
mCursor = dbhelper.getAllRows();
if (myAdapter == null) {
myAdapter = new MyCursorAdapter(this,mCursor);
myListView.setAdapter(myAdapter);
myListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
dbhelper.updateSelected(mCursor.getString(mCursor.getColumnIndex(ContractClass.FeedReaderContract.COLUMN_NAME_ENWORD)));
manageListView();
}
});
} else {
myAdapter.swapCursor(mCursor);
}
}
private void addSomeTestingData() {
if (DatabaseUtils.queryNumEntries(dbhelper.getWritableDatabase(),ContractClass.FeedReaderContract.TABLENAME) > 1) return;
for (int i=0; i < 10; i++) {
dbhelper.addRow("Apple", "Thing that falls from trees");
dbhelper.addRow("Cat", "Something that is furry and sits on mats");
dbhelper.addRow("Bear", "Something that is furry that eats honey but doesn't ssit on a mat");
dbhelper.addRow("Dog", "Something is furry and friendly");
dbhelper.addRow("Echida", "An upside down hedgehog");
dbhelper.addRow("Ferret", "Something that is furry and found up trouser legs");
dbhelper.addRow("Giraffe", "Something that has 5 legs one pointing up");
dbhelper.addRow("Hippo", "An animal that loves mud and water but not humans");
dbhelper.addRow("Ibis", "A white feathered flying thing");
dbhelper.addRow("Jaguar", "A car or a large black cat");
dbhelper.addRow("Kangaroo", "A marsupial that boxes, skips and has a puch for shopping trips");
dbhelper.addRow("Lizard", "A rock dweller");
dbhelper.addRow("Mammoth", "A big hairy elephant now extinct");
dbhelper.addRow("Nuthatch", "A small bird that does not customise nuts so they have hatches.");
dbhelper.addRow("Ostrich", "A l argefast running bird that does not fly");
dbhelper.addRow("Panther", "A skinny pink cat that walks on only two of it's four lehs");
dbhelper.addRow("Queen", "A female rule of a country");
dbhelper.addRow("Rhinocerous", "A Hippo like animal that has a name that is hard to spell");
dbhelper.addRow("Tiger", "A live verion of Winnie the Pooh's friend Tigger");
dbhelper.addRow("Stork", "A skinny ostrich that flies and delivers children through Dream World.");
}
}
}
Obviously the addSomeTestingData method is just for that.
Note that there's hardly any other code. The DB access has all been moved to the DBHelper class.
The crux of the matter is the manageListView method.
First the Cursor used by the adapter is populated.
The Adapter hasn't been instantiated and is therefore null is instantiated and then tied to the ListView.
The OnItemClickListener is added noting that it calls the manageListView method after the database has been updated.
If the Adapter has been instantiated then the swapCursor method is called that tells the adapter that underlying cursor has been changed.
DBHelper.java
public class DBHelper extends SQLiteOpenHelper {
public DBHelper(#Nullable Context context) {
super(context, ContractClass.DBNAME,null,ContractClass.DBVERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(ContractClass.FeedReaderContract.CRTSQL);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public Cursor getAllRows() {
SQLiteDatabase db = this.getWritableDatabase();
return db.query(ContractClass.FeedReaderContract.TABLENAME,null,null,null,null,null,null);
}
public void updateSelected(String selected) {
SQLiteDatabase db = this.getWritableDatabase();
db.execSQL("UPDATE "
+ ContractClass.FeedReaderContract.TABLENAME
+ " SET " + ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED
+ "= CASE " + ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED +
" WHEN 1 THEN 0 ELSE 1 END " +
" WHERE " + ContractClass.FeedReaderContract.COLUMN_NAME_ENWORD + " LIKE ?",
new String[]{selected}
);
}
public long addRow(String enWord, String definition) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(ContractClass.FeedReaderContract.COLUMN_NAME_ENWORD,enWord);
cv.put(ContractClass.FeedReaderContract.COLUMN_NAME_DEFN,definition);
return db.insert(ContractClass.FeedReaderContract.TABLENAME,null,cv);
}
}
Selecting all rows has been moved here as the getAllRows method
The addRow is just to allow some testing data to be added.
The updateSelected method, rather than extracting rows into a Cursor, to drive the updates instead uses a CASE WHEN ELSE END clause to toggle the value and should be more efficient.
Note that instead of MATCH as MATCH is FTS specififc (I believe) LIKE has been used as the underlying table is not an FTS table. You would use MATCH
MyCursorAdapter.java
public class MyCursorAdapter extends CursorAdapter {
public MyCursorAdapter(Context context, Cursor c) {
super(context, c, false);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.row_list_row,parent,false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
if (cursor.getInt(cursor.getColumnIndex(ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED)) < 1) {
view.setBackgroundColor(0xFFF9F9F9);
} else {
view.setBackgroundColor(0xFFD9D9D9);
}
TextView tvBody = view.findViewById(R.id.txtName);
TextView tvPriority = view.findViewById(R.id.txtComment);
TextView tvPriority2 = view.findViewById(R.id.txtThird);
TextView tvPriority3 = view.findViewById(R.id.txtThi);
tvBody.setText(cursor.getString(cursor.getColumnIndex(ContractClass.FeedReaderContract.COLUMN_NAME_ENWORD)));
tvPriority.setText(cursor.getString(cursor.getColumnIndex(ContractClass.FeedReaderContract.COLUMN_NAME_DEFN)));
tvPriority2.setText(cursor.getString(cursor.getColumnIndex(ContractClass.FeedReaderContract._id)));
tvPriority3.setText(cursor.getString(cursor.getColumnIndex(ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED)));
}
}
The main difference is that rather than juggle swapping layouts the background of the view is changed in the bindView method, rather than the newView method.
You need to override getItemViewType(position) if you want to use multiple different view types. If you don't, then the adapter has no way to know whether or not the View instance it is passing as convertView is of the right type, and you will wind up with badly-recycled views.
This doesn't appear to be trivial for CursorAdapter (with which I don't have any experience). I think the right way to do it should be something like this:
override fun getItemViewType(position: Int): Int {
cursor.moveToPosition(position)
val columnIndex = cursor.getColumnIndexOrThrow(ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED)
return when (cursor.getInt(columnIndex)) {
0 -> 0
else -> 1
}
}
I think also that you should change newView() to leverage these types. Leaving what you have should work, but it would be duplicated code.
override fun newView(context: Context, cursor: Cursor, parent: ViewGroup): View {
val layoutId = when (val type = getItemViewType(cursor.position)) {
0 -> R.layout.row_list_row
1 -> R.layout.user_list_row_selected
else -> throw IllegalStateException("unexpected viewType: $type")
}
return LayoutInflater.from(context).inflate(layoutId, parent, false)
}
I'm just starting with Flink CEP and I come from Esper CEP engine. As you may (or not) know, in Esper using their syntax (EPL) you can create a batch or slide window easily, grouping the events in those windows and allowing you to use this events with functions (avg, max, min, ...).
For example, with the following pattern you can create a batch windows of 5 seconds and calculate the average value of the attribute price of all the Stock events that you have received in that specified window.
select avg(price) from Stock#time_batch(5 sec)
The thing is I would like to know how to implement this on Flink CEP. I'm aware that, probably, the goal or approach in Flink CEP is different, so the way to implement this may not be as simple as in Esper CEP.
I have taken a look at the docs regarding to time windows, but I'm not able to implement this windows along with Flink CEP. So, given the following code:
DataStream<Stock> stream = ...; // Consume events from Kafka
// Filtering events with negative price
Pattern<Stock, ?> pattern = Pattern.<Stock>begin("start")
.where(
new SimpleCondition<Stock>() {
public boolean filter(Stock event) {
return event.getPrice() >= 0;
}
}
);
PatternStream<Stock> patternStream = CEP.pattern(stream, pattern);
/**
CREATE A BATCH WINDOW OF 5 SECONDS IN WHICH
I COMPUTE OVER THE AVERAGE PRICES AND, IF IT IS
GREATER THAN A THREESHOLD, AN ALERT IS DETECTED
return avg(allEventsInWindow.getPrice()) > 1;
*/
DataStream<Alert> result = patternStream.select(
new PatternSelectFunction<Stock, Alert>() {
#Override
public Alert select(Map<String, List<Stock>> pattern) throws Exception {
return new Alert(pattern.toString());
}
}
);
How can I create that window in which, from the first one received, I start to calculate the average for the following events within 5 seconds. For example:
t = 0 seconds
Stock(price = 1); (...starting batch window...)
Stock(price = 1);
Stock(price = 1);
Stock(price = 2);
Stock(price = 2);
Stock(price = 2);
t = 5 seconds (...end of batch window...)
Avg = 1.5 => Alert detected!
The average after 5 seconds would be 1.5, and will trigger the alert. How can I code this?
Thanks!
With Flink's CEP library this behavior is not expressible. I would rather recommend using Flink's DataStream or Table API to calculate the averages. Based on that you could again use CEP to generate other events.
final DataStream<Stock> input = env
.fromElements(
new Stock(1L, 1.0),
new Stock(2L, 2.0),
new Stock(3L, 1.0),
new Stock(4L, 2.0))
.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor<Stock>(Time.seconds(0L)) {
#Override
public long extractTimestamp(Stock element) {
return element.getTimestamp();
}
});
final DataStream<Double> windowAggregation = input
.timeWindowAll(Time.milliseconds(2))
.aggregate(new AggregateFunction<Stock, Tuple2<Integer, Double>, Double>() {
#Override
public Tuple2<Integer, Double> createAccumulator() {
return Tuple2.of(0, 0.0);
}
#Override
public Tuple2<Integer, Double> add(Stock value, Tuple2<Integer, Double> accumulator) {
return Tuple2.of(accumulator.f0 + 1, accumulator.f1 + value.getValue());
}
#Override
public Double getResult(Tuple2<Integer, Double> accumulator) {
return accumulator.f1 / accumulator.f0;
}
#Override
public Tuple2<Integer, Double> merge(Tuple2<Integer, Double> a, Tuple2<Integer, Double> b) {
return Tuple2.of(a.f0 + b.f0, a.f1 + b.f1);
}
});
final DataStream<Double> result = windowAggregation.filter((FilterFunction<Double>) value -> value > THRESHOLD);
I am trying to Print the values of warnings that have been detected in Flink
// Generate temperature warnings for each matched warning pattern
DataStream<TemperatureEvent> warnings = tempPatternStream.select(
(Map<String, MonitoringEvent> pattern) -> {
TemperatureEvent first = (TemperatureEvent) pattern.get("first");
return new TemperatureEvent(first.getRackID(), first.getTemperature()) ;
}
);
// Print the warning and alert events to stdout
warnings.print();
I am getting output as below(as per toString of eventSource function)
Rack id = 99 and temprature = 76.0
Can someone tell me, if there is any way I can print the values of DataStream without using print? An example would be, if I only want to print temperature, how can I access Individual elements in DataStream.
Thanks in Advance
I have figured out a way to access individual elements, Lets assume we have a DataStream
HeartRate<Integer,Integer>
It has 2 attributes
private Integer Patient_id ;
private Integer HR;
// Generating a Datasteam using custom function
DataStream<HREvent> hrEventDataStream = envrionment
.addSource(new HRGenerator()).assignTimestampsAndWatermarks(new IngestionTimeExtractor<>());
Assuming that you have Generated a Datasteam using custom function ,now we can print the values of Individual Elements of HeartRateEvent as below
hrEventDataStream.keyBy(new KeySelector<HREvent, Integer>() {
#Override
public Integer getKey(HREvent hrEvent) throws Exception {
return hrEvent.getPatient_id();
}
})
.window(TumblingEventTimeWindows.of(milliseconds(10)))
.apply(new WindowFunction<HREvent, Object, Integer, TimeWindow>() {
#Override
public void apply(Integer integer, TimeWindow timeWindow, Iterable<HREvent> iterable, Collector<Object> collector) throws Exception {
for(HREvent in : iterable){
System.out.println("Patient id = " + in.getPatient_id() + " Heart Rate = " + in.getHR());
}//for
}//apply
});
Hope it Helps !
I was going through the SOQL documentation , but couldn't find query to fetch all the field data of an entity say , Account , like
select * from Account [ SQL syntax ]
Is there a syntax like the above in SOQL to fetch all the data of account , or the only way is to list all the fields ( though there are lot of fields to be queried )
Create a map like this:
Map<String, Schema.SObjectField> fldObjMap = schema.SObjectType.Account.fields.getMap();
List<Schema.SObjectField> fldObjMapValues = fldObjMap.values();
Then you can iterate through fldObjMapValues to create a SOQL query string:
String theQuery = 'SELECT ';
for(Schema.SObjectField s : fldObjMapValues)
{
String theLabel = s.getDescribe().getLabel(); // Perhaps store this in another map
String theName = s.getDescribe().getName();
String theType = s.getDescribe().getType(); // Perhaps store this in another map
// Continue building your dynamic query string
theQuery += theName + ',';
}
// Trim last comma
theQuery = theQuery.subString(0, theQuery.length() - 1);
// Finalize query string
theQuery += ' FROM Account WHERE ... AND ... LIMIT ...';
// Make your dynamic call
Account[] accounts = Database.query(theQuery);
superfell is correct, there is no way to directly do a SELECT *. However, this little code recipe will work (well, I haven't tested it but I think it looks ok). Understandably Force.com wants a multi-tenant architecture where resources are only provisioned as explicitly needed - not easily by doing SELECT * when usually only a subset of fields are actually needed.
You have to specify the fields, if you want to build something dynamic the describeSObject call returns the metadata about all the fields for an object, so you can build the query from that.
I use the Force.com Explorer and within the schema filter you can click the checkbox next to the TableName and it will select all the fields and insert into your query window - I use this as a shortcut to typeing it all out - just copy and paste from the query window. Hope this helps.
In case anyone was looking for a C# approach, I was able to use reflection and come up with the following:
public IEnumerable<String> GetColumnsFor<T>()
{
return typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
.Where(x => !Attribute.IsDefined(x, typeof(System.Xml.Serialization.XmlIgnoreAttribute))) // Exclude the ignored properties
.Where(x => x.DeclaringType != typeof(sObject)) // & Exclude inherited sObject propert(y/ies)
.Where(x => x.PropertyType.Namespace != typeof(Account).Namespace) // & Exclude properties storing references to other objects
.Select(x => x.Name);
}
It appears to work for the objects I've tested (and matches the columns generated by the API test). From there, it's about creating the query:
/* assume: this.server = new sForceService(); */
public IEnumerable<T> QueryAll<T>(params String[] columns)
where T : sObject
{
String soql = String.Format("SELECT {0} FROM {1}",
String.Join(", ", GetColumnsFor<T>()),
typeof(T).Name
);
this.service.QueryOptionsValue = new QueryOptions
{
batchsize = 250,
batchSizeSpecified = true
};
ICollection<T> results = new HashSet<T>();
try
{
Boolean done = false;
QueryResult queryResult = this.service.queryAll(soql);
while (!finished)
{
sObject[] records = queryResult.records;
foreach (sObject record in records)
{
T entity = entity as T;
if (entity != null)
{
results.Add(entity);
}
}
done &= queryResult.done;
if (!done)
{
queryResult = this.service.queryMode(queryResult.queryLocator);
}
}
}
catch (Exception ex)
{
throw; // your exception handling
}
return results;
}
For me it was the first time with Salesforce today and I came up with this in Java:
/**
* #param o any class that extends {#link SObject}, f.ex. Opportunity.class
* #return a list of all the objects of this type
*/
#SuppressWarnings("unchecked")
public <O extends SObject> List<O> getAll(Class<O> o) throws Exception {
// get the objectName; for example "Opportunity"
String objectName= o.getSimpleName();
// this will give us all the possible fields of this type of object
DescribeSObjectResult describeSObject = connection.describeSObject(objectName);
// making the query
String query = "SELECT ";
for (Field field : describeSObject.getFields()) { // add all the fields in the SELECT
query += field.getName() + ',';
}
// trim last comma
query = query.substring(0, query.length() - 1);
query += " FROM " + objectName;
SObject[] records = connection.query(query).getRecords();
List<O> result = new ArrayList<O>();
for (SObject record : records) {
result.add((O) record);
}
return result;
}
I used following to get complete records-
query_all("Select Id, Name From User_Profile__c")
To get complete fields of record, we have to mention those fields as mentioned here-
https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select.htm
Hope will help you !!!