diff options
Diffstat (limited to 'predicate-search-core/src/main/java/com/yahoo/document/predicate/BinaryFormat.java')
-rw-r--r-- | predicate-search-core/src/main/java/com/yahoo/document/predicate/BinaryFormat.java | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/predicate-search-core/src/main/java/com/yahoo/document/predicate/BinaryFormat.java b/predicate-search-core/src/main/java/com/yahoo/document/predicate/BinaryFormat.java new file mode 100644 index 00000000000..89dcbc59d99 --- /dev/null +++ b/predicate-search-core/src/main/java/com/yahoo/document/predicate/BinaryFormat.java @@ -0,0 +1,167 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.document.predicate; + +import com.yahoo.slime.Cursor; +import com.yahoo.slime.Inspector; +import com.yahoo.slime.Slime; + +import java.util.Objects; + +/** + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a> + */ +public class BinaryFormat { + + final static String NODE_TYPE = "type"; + final static String KEY = "key"; + final static String SET = "feature_set"; + final static String RANGE_MIN = "range_min"; + final static String RANGE_MAX = "range_max"; + final static String CHILDREN = "children"; + final static String PARTITIONS = "partitions"; + final static String EDGE_PARTITIONS = "edge_partitions"; + final static String HASHED_PARTITIONS = "hashed_partitions"; + final static String HASHED_EDGE_PARTITIONS = "hashed_edge_partitions"; + final static String HASH = "hash"; + final static String PAYLOAD = "payload"; + final static String LABEL = "label"; + final static String VALUE = "value"; + final static String LOWER_BOUND = "lower_bound"; + final static String UPPER_BOUND = "upper_bound"; + + final static int TYPE_CONJUNCTION = 1; + final static int TYPE_DISJUNCTION = 2; + final static int TYPE_NEGATION = 3; + final static int TYPE_FEATURE_SET = 4; + final static int TYPE_FEATURE_RANGE = 5; + final static int TYPE_TRUE = 6; + final static int TYPE_FALSE = 7; + + public static byte[] encode(Predicate predicate) { + Objects.requireNonNull(predicate, "predicate"); + Slime slime = new Slime(); + encode(predicate, slime.setObject()); + return com.yahoo.slime.BinaryFormat.encode(slime); + } + + public static Predicate decode(byte[] buf) { + Objects.requireNonNull(buf, "buf"); + Slime slime = com.yahoo.slime.BinaryFormat.decode(buf); + return decode(slime.get()); + } + + private static Predicate decode(Inspector in) { + switch ((int)in.field(NODE_TYPE).asLong()) { + case TYPE_CONJUNCTION: + Conjunction conjunction = new Conjunction(); + in = in.field(CHILDREN); + for (int i = 0, len = in.children(); i < len; ++i) { + conjunction.addOperand(decode(in.entry(i))); + } + return conjunction; + + case TYPE_DISJUNCTION: + Disjunction disjunction = new Disjunction(); + in = in.field(CHILDREN); + for (int i = 0, len = in.children(); i < len; ++i) { + disjunction.addOperand(decode(in.entry(i))); + } + return disjunction; + + case TYPE_NEGATION: + return new Negation(decode(in.field(CHILDREN).entry(0))); + + case TYPE_FEATURE_RANGE: + FeatureRange featureRange = new FeatureRange(in.field(KEY).asString()); + if (in.field(RANGE_MIN).valid()) { + featureRange.setFromInclusive(in.field(RANGE_MIN).asLong()); + } + if (in.field(RANGE_MAX).valid()) { + featureRange.setToInclusive(in.field(RANGE_MAX).asLong()); + } + Inspector p_in = in.field(PARTITIONS); + for (int i = 0, len = p_in.children(); i < len; ++i) { + featureRange.addPartition(new RangePartition(p_in.entry(i).asString())); + } + p_in = in.field(EDGE_PARTITIONS); + for (int i = 0, len = p_in.children(); i < len; ++i) { + Inspector obj = p_in.entry(i); + featureRange.addPartition(new RangeEdgePartition( + obj.field(LABEL).asString(), obj.field(VALUE).asLong(), + (int)obj.field(LOWER_BOUND).asLong(), (int)obj.field(UPPER_BOUND).asLong())); + } + return featureRange; + + case TYPE_FEATURE_SET: + FeatureSet featureSet = new FeatureSet(in.field(KEY).asString()); + in = in.field(SET); + for (int i = 0, len = in.children(); i < len; ++i) { + featureSet.addValue(in.entry(i).asString()); + } + return featureSet; + + case TYPE_TRUE: + return new BooleanPredicate(true); + + case TYPE_FALSE: + return new BooleanPredicate(false); + + default: + throw new UnsupportedOperationException(String.valueOf(in.field(NODE_TYPE).asLong())); + } + } + + private static void encode(Predicate predicate, Cursor out) { + if (predicate instanceof Conjunction) { + out.setLong(NODE_TYPE, TYPE_CONJUNCTION); + out = out.setArray(CHILDREN); + for (Predicate operand : ((Conjunction)predicate).getOperands()) { + encode(operand, out.addObject()); + } + } else if (predicate instanceof Disjunction) { + out.setLong(NODE_TYPE, TYPE_DISJUNCTION); + out = out.setArray(CHILDREN); + for (Predicate operand : ((Disjunction)predicate).getOperands()) { + encode(operand, out.addObject()); + } + } else if (predicate instanceof FeatureRange) { + FeatureRange range = (FeatureRange) predicate; + out.setLong(NODE_TYPE, TYPE_FEATURE_RANGE); + out.setString(KEY, range.getKey()); + Long from = range.getFromInclusive(); + if (from != null) { + out.setLong(RANGE_MIN, from); + } + Long to = range.getToInclusive(); + if (to != null) { + out.setLong(RANGE_MAX, to); + } + Cursor p_out = out.setArray(HASHED_PARTITIONS); + for (RangePartition p : range.getPartitions()) { + p_out.addLong(PredicateHash.hash64(p.getLabel())); + } + p_out = out.setArray(HASHED_EDGE_PARTITIONS); + for (RangeEdgePartition p : range.getEdgePartitions()) { + Cursor obj = p_out.addObject(); + obj.setLong(HASH, PredicateHash.hash64(p.getLabel())); + obj.setLong(VALUE, p.getValue()); + obj.setLong(PAYLOAD, p.encodeBounds()); + } + } else if (predicate instanceof FeatureSet) { + out.setLong(NODE_TYPE, TYPE_FEATURE_SET); + out.setString(KEY, ((FeatureSet)predicate).getKey()); + out = out.setArray(SET); + for (String value : ((FeatureSet)predicate).getValues()) { + out.addString(value); + } + } else if (predicate instanceof Negation) { + out.setLong(NODE_TYPE, TYPE_NEGATION); + out = out.setArray(CHILDREN); + encode(((Negation)predicate).getOperand(), out.addObject()); + } else if (predicate instanceof BooleanPredicate) { + out.setLong(NODE_TYPE, ((BooleanPredicate)predicate).getValue() ? TYPE_TRUE : TYPE_FALSE); + } else { + throw new UnsupportedOperationException(predicate.getClass().getName()); + } + } +} |