dido.operators.LeftStreamJoin Maven / Gradle / Ivy
The newest version!
package dido.operators;
import dido.data.Concatenator;
import dido.data.GenericData;
import dido.data.IndexedData;
import dido.data.SubData;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
public class LeftStreamJoin implements StreamJoin {
private final Consumer> primary = new PrimaryConsumer();
private final Consumer> secondary = new SecondaryConsumer();
private final Map, SingleJoin> data = new ConcurrentHashMap<>();
private final Function, GenericData> primaryIndices;
private final Function, GenericData> foreignIndices;
private final Function, GenericData> secondaryIndices;
private volatile Consumer super GenericData> to;
private final Concatenator.Factory concatenator = Concatenator.withSettings()
.skipDuplicates(true).factory();
private LeftStreamJoin(With with) {
this.primaryIndices = with.primaryIndices();
this.foreignIndices = with.foreignIndices();
this.secondaryIndices = with.secondaryIndices();
}
public static class With {
private int[] primaryIndices;
private F[] primaryFields;
private int[] foreignIndices;
private F[] foreignFields;
private int[] secondaryIndices;
private F[] secondaryFields;
public With primaryIndices(int... primaryIndices) {
this.primaryIndices = primaryIndices;
return this;
}
public With foreignIndices(int... foreignIndices) {
this.foreignIndices = foreignIndices;
return this;
}
public With secondaryIndices(int... secondaryIndices) {
this.secondaryIndices = secondaryIndices;
return this;
}
public With primaryFields(F... primaryFields) {
this.primaryFields = primaryFields;
return this;
}
public With foreignFields(F... foreignFields) {
this.foreignFields = foreignFields;
return this;
}
public With secondaryFields(F... secondaryFields) {
this.secondaryFields = secondaryFields;
return this;
}
private Function, GenericData> primaryIndices() {
if (primaryIndices == null) {
return SubData.ofFields(Objects.requireNonNull(primaryFields));
}
else {
return SubData.ofIndices(primaryIndices);
}
}
private Function, GenericData> foreignIndices() {
if (foreignIndices == null) {
return SubData.ofFields(Objects.requireNonNull(foreignFields));
}
else {
return SubData.ofIndices(foreignIndices);
}
}
private Function, GenericData> secondaryIndices() {
if (secondaryIndices == null) {
return SubData.ofFields(Objects.requireNonNull(secondaryFields));
}
else {
return SubData.ofIndices(secondaryIndices);
}
}
public StreamJoin make() {
return new LeftStreamJoin<>(this);
}
}
public static With with() {
return new With<>();
}
@Override
public Consumer> getPrimary() {
return primary;
}
@Override
public Consumer> getSecondary() {
return secondary;
}
@Override
public void setTo(Consumer super GenericData> to) {
this.to = to;
}
class PrimaryConsumer implements Consumer> {
@Override
public void accept(IndexedData primaryData) {
IndexedData keyOfPrimary = primaryIndices.apply(primaryData);
IndexedData foreignKey = foreignIndices.apply(primaryData);
SingleJoin singleJoin = data.computeIfAbsent(foreignKey, k -> new SingleJoin<>());
singleJoin.primaries.mappedByKey.put(keyOfPrimary, primaryData);
// ok so long as this is always called on the same thread.
if (singleJoin.secondary != null) {
to.accept(concatenator.concat(primaryData, singleJoin.secondary));
}
}
}
class SecondaryConsumer implements Consumer> {
@Override
public void accept(IndexedData secondaryData) {
IndexedData keyOfSecondary = secondaryIndices.apply(secondaryData);
SingleJoin singleJoin = data.computeIfAbsent(keyOfSecondary, k -> new SingleJoin<>());
singleJoin.secondary = secondaryData;
singleJoin.primaries.mappedByKey.values()
.forEach(primary -> to.accept(concatenator.concat(primary, secondaryData)));
}
}
static class Primaries {
private final Map, IndexedData> mappedByKey = new ConcurrentHashMap<>();
}
static class SingleJoin {
private final Primaries primaries = new Primaries<>();
private volatile IndexedData secondary;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy