static void write(Endpoint endpoint, JsonGenerator writer) throws IOException {
    writer.writeStartObject();
    if (endpoint.serviceName() != null) {
      writer.writeStringField("serviceName", endpoint.serviceName());
    }
    if (endpoint.ipv4() != null) writer.writeStringField("ipv4", endpoint.ipv4());
    if (endpoint.ipv6() != null) writer.writeStringField("ipv6", endpoint.ipv6());
    if (endpoint.portAsInt() != 0) writer.writeNumberField("port", endpoint.portAsInt());
    writer.writeEndObject();
  }
In order to allow systems like Kibana to search by timestamp, we add a field "timestamp_millis"
when storing. The cheapest way to do this without changing the codec is prefixing it to the
json. For example. {"traceId":"... becomes {"timestamp_millis":12345,"traceId":"...

<p>Tags are stored as a dictionary. Since some tag names will include inconsistent number of
dots (ex "error" and perhaps "error.message"), we cannot index them naturally with
elasticsearch. Instead, we add an index-only (non-source) field of {@code _q} which includes
valid search queries. For example, the tag {@code error -> 500} results in {@code
"_q":["error", "error=500"]}. This matches the input query syntax, and can be checked manually
with curl.

<p>Ex {@code curl -s localhost:9200/zipkin:span-2017-08-11/_search?q=_q:error=500}

@param searchEnabled encodes timestamp_millis and _q when non-empty
zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/internal/BulkIndexWriter.java