docs: public List<Object> query(final JointIndexQuery.Subquery query, final BackendTransaction tx) {
          IndexType index = query.getIndex();
          if (index.isCompositeIndex()) {
              MultiKeySliceQuery sq = query.getCompositeQuery();
              List<EntryList> rs = sq.execute(tx);
              List<Object> results = new ArrayList<Object>(rs.get(0).size());
              for (EntryList r : rs) {
                  for (java.util.Iterator<Entry> iterator = r.reuseIterator(); iterator.hasNext(); ) {
                      Entry entry = iterator.next();
                      ReadBuffer entryValue = entry.asReadBuffer();
                      entryValue.movePositionTo(entry.getValuePosition());
                      switch(index.getElement()) {
                          case VERTEX:
                              results.add(VariableLong.readPositive(entryValue));
                              break;
                          default:
                              results.add(bytebuffer2RelationId(entryValue));
                      }
                  }
              }
              return results;
          } else {
              List<String> r = tx.indexQuery(((MixedIndexType) index).getBackingIndexName(), query.getMixedQuery());
              List<Object> result = new ArrayList<Object>(r.size());
              for (String id : r) result.add(string2ElementId(id));
              return result;
          }
      }
  
      public MultiKeySliceQuery getQuery(final CompositeIndexType index, List<Object[]> values) {
          List<KeySliceQuery> ksqs = new ArrayList<KeySliceQuery>(values.size());
          for (Object[] value : values) {
              ksqs.add(new KeySliceQuery(getIndexKey(index,value), BufferUtil.zeroBuffer(1), BufferUtil.oneBuffer(1)));
          }
          return new MultiKeySliceQuery(ksqs);
      }
  
      public IndexQuery getQuery(final MixedIndexType index, final Condition condition, final OrderList orders) {
          Condition newCondition = ConditionUtil.literalTransformation(condition,
                  new Function<Condition<TitanElement>, Condition<TitanElement>>() {
                      @Nullable
                      @Override
                      public Condition<TitanElement> apply(@Nullable Condition<TitanElement> condition) {
                          Preconditions.checkArgument(condition instanceof PredicateCondition);
                          PredicateCondition pc = (PredicateCondition) condition;
                          PropertyKey key = (PropertyKey) pc.getKey();
                          return new PredicateCondition<String, TitanElement>(key2Field(index,key), pc.getPredicate(), pc.getValue());
                      }
                  });
          ImmutableList<IndexQuery.OrderEntry> newOrders = IndexQuery.NO_ORDER;
          if (!orders.isEmpty() && GraphCentricQueryBuilder.indexCoversOrder(index,orders)) {
              ImmutableList.Builder<IndexQuery.OrderEntry> lb = ImmutableList.builder();
              for (int i = 0; i < orders.size(); i++) {
                  lb.add(new IndexQuery.OrderEntry(key2Field(index,orders.getKey(i)), orders.getOrder(i), orders.getKey(i).dataType()));
              }
              newOrders = lb.build();
          }
          return new IndexQuery(index.getStoreName(), newCondition, newOrders);
      }
  //
  //
  //
  //    public IndexQuery getQuery(String index, final ElementCategory resultType, final Condition condition, final OrderList orders) {
  //        if (isStandardIndex(index)) {
  //            Preconditions.checkArgument(orders.isEmpty());
  //            return new IndexQuery(getStoreName(resultType), condition, IndexQuery.NO_ORDER);
  //        } else {
  //            Condition newCondition = ConditionUtil.literalTransformation(condition,
  //                    new Function<Condition<TitanElement>, Condition<TitanElement>>() {
  //                        @Nullable
  //                        @Override
  //                        public Condition<TitanElement> apply(@Nullable Condition<TitanElement> condition) {
  //                            Preconditions.checkArgument(condition instanceof PredicateCondition);
  //                            PredicateCondition pc = (PredicateCondition) condition;
  //                            TitanKey key = (TitanKey) pc.getKey();
  //                            return new PredicateCondition<String, TitanElement>(key2Field(key), pc.getPredicate(), pc.getValue());
  //                        }
  //                    });
  //            ImmutableList<IndexQuery.OrderEntry> newOrders = IndexQuery.NO_ORDER;
  //            if (!orders.isEmpty()) {
  //                ImmutableList.Builder<IndexQuery.OrderEntry> lb = ImmutableList.builder();
  //                for (int i = 0; i < orders.size(); i++) {
  //                    lb.add(new IndexQuery.OrderEntry(key2Field(orders.getKey(i)), orders.getOrder(i), orders.getKey(i).getDataType()));
  //                }
  //                newOrders = lb.build();
  //            }
  //            return new IndexQuery(getStoreName(resultType), newCondition, newOrders);
  //        }
  //    }
  
      public Iterable<RawQuery.Result> executeQuery(IndexQueryBuilder query, final ElementCategory resultType,
                                                    final BackendTransaction backendTx, final StandardTitanTx transaction) {
          MixedIndexType index = getMixedIndex(query.getIndex(), transaction);
          Preconditions.checkArgument(index.getElement()==resultType,"Index is not configured for the desired result type: %s",resultType);
          String backingIndexName = index.getBackingIndexName();
          IndexProvider indexInformation = (IndexProvider) mixedIndexes.get(backingIndexName);
  
          StringBuffer qB = new StringBuffer(query.getQuery());
          final String prefix = query.getPrefix();
          Preconditions.checkNotNull(prefix);
          //Convert query string by replacing
          int replacements = 0;
          int pos = 0;
          while (pos<qB.length()) {
              pos = qB.indexOf(prefix,pos);
              if (pos<0) break;
  
              int startPos = pos;
              pos += prefix.length();
              StringBuilder keyBuilder = new StringBuilder();
              boolean quoteTerminated = qB.charAt(pos)=='"';
              if (quoteTerminated) pos++;
              while (pos<qB.length() &&
                      (Character.isLetterOrDigit(qB.charAt(pos))
                              || (quoteTerminated && qB.charAt(pos)!='"') || qB.charAt(pos) == '*' ) ) {
                  keyBuilder.append(qB.charAt(pos));
                  pos++;
              }
              if (quoteTerminated) pos++;
              int endPos = pos;
              String keyname = keyBuilder.toString();
              Preconditions.checkArgument(StringUtils.isNotBlank(keyname),
                      "Found reference to empty key at position [%s]",startPos);
              String replacement;
              if(keyname.equals("*")) {
                  replacement = indexInformation.getFeatures().getWildcardField();
              }
              else if (transaction.containsRelationType(keyname)) {
                  PropertyKey key = transaction.getPropertyKey(keyname);
                  Preconditions.checkNotNull(key);
                  Preconditions.checkArgument(index.indexesKey(key),
                          "The used key [%s] is not indexed in the targeted index [%s]",key.name(),query.getIndex());
                  replacement = key2Field(index,key);
              } else {
                  Preconditions.checkArgument(query.getUnknownKeyName()!=null,
                          "Found reference to non-existant property key in query at position [%s]: %s",startPos,keyname);
                  replacement = query.getUnknownKeyName();
              }
              Preconditions.checkArgument(StringUtils.isNotBlank(replacement));
  
              qB.replace(startPos,endPos,replacement);
              pos = startPos+replacement.length();
              replacements++;
          }
  
          String queryStr = qB.toString();
          if (replacements<=0) log.warn("Could not convert given {} index query: [{}]",resultType, query.getQuery());
          log.info("Converted query string with {} replacements: [{}] => [{}]",replacements,query.getQuery(),queryStr);
          RawQuery rawQuery=new RawQuery(index.getStoreName(),queryStr,query.getParameters());
          if (query.hasLimit()) rawQuery.setLimit(query.getLimit());
          rawQuery.setOffset(query.getOffset());
          return Iterables.transform(backendTx.rawQuery(index.getBackingIndexName(), rawQuery), new Function<RawQuery.Result<String>, RawQuery.Result>() {
              @Nullable
              @Override
              public RawQuery.Result apply(@Nullable RawQuery.Result<String> result) {
                  return new RawQuery.Result(string2ElementId(result.getResult()), result.getScore());
              }
          });
      }
  
  
      /* ################################################
                  Utility Functions
      ################################################### */
  
      private static final MixedIndexType getMixedIndex(String indexName, StandardTitanTx transaction) {
          IndexType index = ManagementSystem.getGraphIndexDirect(indexName, transaction);
          Preconditions.checkArgument(index!=null,"Index with name [%s] is unknown or not configured properly",indexName);
          Preconditions.checkArgument(index.isMixedIndex());
          return (MixedIndexType)index;
      }
  
      private static final String element2String(TitanElement element) {
          return element2String(element.id());
      }
  
      private static final String element2String(Object elementId) {
          Preconditions.checkArgument(elementId instanceof Long || elementId instanceof RelationIdentifier);
          if (elementId instanceof Long) return longID2Name((Long)elementId);
          else return ((RelationIdentifier) elementId).toString();
      }
  
      private static final Object string2ElementId(String str) {
          if (str.contains(RelationIdentifier.TOSTRING_DELIMITER)) return RelationIdentifier.parse(str);
          else return name2LongID(str);
      }
  
      private static final String key2Field(MixedIndexType index, PropertyKey key) {
          return key2Field(index.getField(key));
      }
  
      private static final String key2Field(ParameterIndexField field) {
          assert field!=null;
          return ParameterType.MAPPED_NAME.findParameter(field.getParameters(),keyID2Name(field.getFieldKey()));
      }
  
      private static final String keyID2Name(PropertyKey key) {
          return longID2Name(key.longId());
      }
  
      private static final String longID2Name(long id) {
          Preconditions.checkArgument(id > 0);
          return LongEncoding.encode(id);
      }
  
      private static final long name2LongID(String name) {
          return LongEncoding.decode(name);
      }
  
  
      private final StaticBuffer getIndexKey(CompositeIndexType index, RecordEntry[] record) {
          return getIndexKey(index,IndexRecords.getValues(record));
      }
  
      private final StaticBuffer getIndexKey(CompositeIndexType index, Object[] values) {
          DataOutput out = serializer.getDataOutput(8*DEFAULT_OBJECT_BYTELEN + 8);
          VariableLong.writePositive(out, index.getID());
          IndexField[] fields = index.getFieldKeys();
          Preconditions.checkArgument(fields.length>0 && fields.length==values.length);
          for (int i = 0; i < fields.length; i++) {
              IndexField f = fields[i];
              Object value = values[i];
              Preconditions.checkNotNull(value);
              if (AttributeUtil.hasGenericDataType(f.getFieldKey())) {
                  out.writeClassAndObject(value);
              } else {
                  assert value.getClass().equals(f.getFieldKey().dataType()) : value.getClass() + " - " + f.getFieldKey().dataType();
                  out.writeObjectNotNull(value);
              }
          }
          StaticBuffer key = out.getStaticBuffer();
          if (hashKeys) key = HashingUtil.hashPrefixKey(hashLength,key);
          return key;
      }
  
      public long getIndexIdFromKey(StaticBuffer key) {
          if (hashKeys) key = HashingUtil.getKey(hashLength,key);
          return VariableLong.readPositive(key.asReadBuffer());
      }
  
      private final Entry getIndexEntry(CompositeIndexType index, RecordEntry[] record, TitanElement element) {
          DataOutput out = serializer.getDataOutput(1+8+8*record.length+4*8);
          out.putByte(FIRST_INDEX_COLUMN_BYTE);
          if (index.getCardinality()!=Cardinality.SINGLE) {
              VariableLong.writePositive(out,element.longId());
              if (index.getCardinality()!=Cardinality.SET) {
                  for (RecordEntry re : record) {
                      VariableLong.writePositive(out,re.relationId);
                  }
              }
          }
          int valuePosition=out.getPosition();
          if (element instanceof TitanVertex) {
              VariableLong.writePositive(out,element.longId());
          } else {
              assert element instanceof TitanRelation;
              RelationIdentifier rid = (RelationIdentifier)element.id();
              long[] longs = rid.getLongRepresentation();
              Preconditions.checkArgument(longs.length == 3 || longs.length == 4);
              for (int i = 0; i < longs.length; i++) VariableLong.writePositive(out, longs[i]);
          }
          return new StaticArrayEntry(out.getStaticBuffer(),valuePosition);
      }
  
      private static final RelationIdentifier bytebuffer2RelationId(ReadBuffer b) {
          long[] relationId = new long[4];
          for (int i = 0; i < 3; i++) relationId[i] = VariableLong.readPositive(b);
          if (b.hasRemaining()) relationId[3] = VariableLong.readPositive(b);
          else relationId = Arrays.copyOfRange(relationId,0,3);
          return RelationIdentifier.get(relationId);
      }
  
  
  }