docs: private void computeUnion() {
      // key = flattened tags, array of queries.size()
      final ByteMap<ExpressionDataPoint[]> ordered_union = 
          new ByteMap<ExpressionDataPoint[]>(); 
  
      final Iterator<ITimeSyncedIterator> it = queries.values().iterator();
      while (it.hasNext()) {
        final ITimeSyncedIterator sub = it.next();
        final ExpressionDataPoint[] dps = sub.values();
        final ByteMap<Integer> local_tags = new ByteMap<Integer>();
        
        for (int i = 0; i < sub.size(); i++) {
          final byte[] key = flattenTags(union_on_query_tagks, include_agg_tags, 
              dps[i], sub);
          local_tags.put(key, i);
          ExpressionDataPoint[] udps = ordered_union.get(key);
          if (udps == null) {
            udps = new ExpressionDataPoint[queries.size()];
            ordered_union.put(key, udps);
          }
          udps[sub.getIndex()] = dps[i];
        }
      }
      
      if (ordered_union.size() < 1) {
        // if no data, just stop here
        return;
      }
      
      setCurrentAndMeta(ordered_union);
    }