aboutsummaryrefslogtreecommitdiffstats
path: root/predicate-search-core/src/main/java/com/yahoo/document/predicate/BinaryFormat.java
diff options
context:
space:
mode:
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.java167
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());
+ }
+ }
+}