/*
* This file is part of ALOE.
*
* ALOE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* ALOE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with ALOE. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (c) 2012 SCCL, University of Washington (http://depts.washington.edu/sccl)
*/
package etc.aloe.cscw2013;
import etc.aloe.data.Message;
import etc.aloe.data.MessageSet;
import etc.aloe.data.Segment;
import etc.aloe.data.SegmentSet;
import etc.aloe.processes.SegmentResolution;
import etc.aloe.processes.Segmentation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Segments messages according to a time threshold. Messages separated by more
* than the threshold go into different segments. Can optionally separate
* messages by participant as well.
*
* In order for labels to be applied to segments, be sure to set the segment
* resolution procedure.
*
* @author Michael Brooks <mjbrooks@uw.edu>
*/
public class ThresholdSegmentation implements Segmentation {
private final int thresholdSeconds;
private final boolean byParticipant;
private SegmentResolution resolution;
/**
* Construct a new ThresholdSegmentation.
*
* @param thresholdSeconds The number of segments to use as the segmentation
* threshold.
* @param byParticipant True if messages should be separated by participant.
*/
public ThresholdSegmentation(int thresholdSeconds, boolean byParticipant) {
this.thresholdSeconds = thresholdSeconds;
this.byParticipant = byParticipant;
}
/**
* Return a list of messages sorted by participant name (ascending).
*
* @param original
* @return
*/
protected List<Message> sortByParticipant(List<Message> original) {
List<Message> messages = new ArrayList<Message>(original);
Collections.sort(messages, new Comparator<Message>() {
@Override
public int compare(Message o1, Message o2) {
return o1.getParticipant().compareTo(o2.getParticipant());
}
});
return messages;
}
/**
* Return a list of messages sorted by time (ascending).
*
* @param original
* @return
*/
protected List<Message> sortByTime(List<Message> original) {
List<Message> messages = new ArrayList<Message>(original);
Collections.sort(messages, new Comparator<Message>() {
@Override
public int compare(Message o1, Message o2) {
return o1.getTimestamp().compareTo(o2.getTimestamp());
}
});
return messages;
}
@Override
public SegmentSet segment(MessageSet messageSet) {
System.out.println("Segmenting with " + thresholdSeconds + " second threshold," + (byParticipant ? "" : " not") + " separating by participant.");
List<Message> messages = sortByTime(messageSet.getMessages());
if (byParticipant) {
messages = sortByParticipant(messages);
}
SegmentSet segments = new SegmentSet();
Segment current = new Segment();
long lastTime = 0;
String lastParticipant = null;
int numLabeled = 0;
for (Message message : messages) {
long msgSeconds = message.getTimestamp().getTime() / 1000;
long diffSeconds = (msgSeconds - lastTime);
boolean newSegment = false;
if (lastTime > 0 && diffSeconds > thresholdSeconds) {
newSegment = true;
}
if (byParticipant && lastParticipant != null && !lastParticipant.equals(message.getParticipant())) {
newSegment = true;
}
if (newSegment) {
if (this.resolution != null) {
current.setTrueLabel(this.resolution.resolveLabel(current));
if (current.hasTrueLabel()) {
numLabeled++;
}
}
segments.add(current);
current = new Segment();
}
lastTime = msgSeconds;
lastParticipant = message.getParticipant();
current.add(message);
}
if (current.getMessages().size() > 0) {
if (this.resolution != null) {
current.setTrueLabel(this.resolution.resolveLabel(current));
if (current.hasTrueLabel()) {
numLabeled++;
}
}
segments.add(current);
}
System.out.println("Grouped messages into " + segments.size() + " segments (" + numLabeled + " labeled).");
return segments;
}
@Override
public void setSegmentResolution(SegmentResolution resolution) {
this.resolution = resolution;
}
}