All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.yahoo.document.predicate.BinaryFormat Maven / Gradle / Ivy

The newest version!
// Copyright Vespa.ai. 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 Simon Thoresen Hult
 */
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());
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy