Add associative lookup of columns for arbitrary (and more intuitive) ordering.

% curl 'localhost:9200/_cat/nodes?v&headers=jdk,ip,name'
  jdk      ip        name
  1.7.0_40 127.0.0.1 Mordo, Karl

Closes #4433.
This commit is contained in:
Andrew Raines 2013-12-23 12:14:25 -06:00
parent c2b41f8ad9
commit 08ddfcd731
2 changed files with 82 additions and 48 deletions

View File

@ -20,12 +20,10 @@
package org.elasticsearch.common;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import org.elasticsearch.ElasticSearchIllegalArgumentException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
*/
@ -34,6 +32,8 @@ public class Table {
protected List<Cell> headers = new ArrayList<Cell>();
protected List<List<Cell>> rows = new ArrayList<List<Cell>>();
protected Map<String,List<Cell>> map = Maps.newHashMap();
protected List<Cell> currentCells;
protected boolean inHeaders = false;
@ -48,6 +48,18 @@ public class Table {
inHeaders = false;
headers = currentCells;
currentCells = null;
/* Create associative structure for columns that
* contain the same cells as the rows:
*
* header1 => [Cell, Cell, ...]
* header2 => [Cell, Cell, ...]
* header3 => [Cell, Cell, ...]
*/
for (Cell header : headers) {
map.put((String) header.value, new ArrayList<Cell>());
}
return this;
}
@ -75,6 +87,13 @@ public class Table {
public Table addCell(Cell cell) {
currentCells.add(cell);
// If we're in a value row, also populate the named column.
if (!inHeaders) {
String hdr = (String) headers.get(currentCells.indexOf(cell)).value;
map.get(hdr).add(cell);
}
return this;
}
@ -111,7 +130,7 @@ public class Table {
mAttr.put(sAttr.substring(0, idx), sAttr.substring(idx + 1));
}
}
currentCells.add(new Cell(value, mAttr));
addCell(new Cell(value, mAttr));
return this;
}
@ -119,7 +138,9 @@ public class Table {
return this.headers;
}
public Iterable<List<Cell>> getRows() {
public Iterable<List<Cell>> rowIterator() { return rows; }
public List<List<Cell>> getRows() {
return rows;
}
@ -127,6 +148,20 @@ public class Table {
return (List<Cell>[]) rows.toArray();
}
public Map<String, List<Cell>> getAsMap() { return this.map; }
public List<Cell> getHeadersFromNames(List<String> headerNames) {
List<Cell> hdrs = new ArrayList<Cell>();
for (String hdrToFind : headerNames) {
for (Cell header : headers) {
if (((String) header.value).equalsIgnoreCase(hdrToFind)) {
hdrs.add(header);
}
}
}
return hdrs;
}
public Table addTable(Table t2) {
Table t1 = this;
Table t = new Table();

View File

@ -29,9 +29,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
/**
*/
@ -47,19 +45,16 @@ public class RestTable {
public static RestResponse buildXContentBuilder(Table table, RestRequest request, RestChannel channel) throws Exception {
XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
Set<String> displayHeaders = buildDisplayHeaders(table, request);
List<String> displayHeaders = buildDisplayHeaders(table, request);
List<Table.Cell> headers = table.getHeaders();
builder.startArray();
for (List<Table.Cell> row : table.getRows()) {
for (int row = 0; row < table.getRows().size(); row++) {
builder.startObject();
for (int i = 0; i < headers.size(); i++) {
String headerName = headers.get(i).value.toString();
if (displayHeaders.contains(headerName)) {
builder.field(headerName, renderValue(request, row.get(i).value));
}
for (String header : displayHeaders) {
builder.field(header, renderValue(request, table.getAsMap().get(header).get(row).value));
}
builder.endObject();
}
builder.endArray();
return new XContentRestResponse(request, RestStatus.OK, builder);
@ -81,42 +76,42 @@ public class RestTable {
return new StringRestResponse(RestStatus.OK, out.toString());
}
int[] width = buildWidths(table, request, verbose);
Set<String> displayHeaders = buildDisplayHeaders(table, request);
List<String> displayHeaders = buildDisplayHeaders(table, request);
int[] width = buildWidths(table, request, verbose, displayHeaders);
int col = 0;
StringBuilder out = new StringBuilder();
if (verbose) {
// print the headers
for (int i = 0; i < width.length; i++) {
String headerName = table.getHeaders().get(i).value.toString();
if (displayHeaders.contains(headerName)) {
pad(table.getHeaders().get(i), width[i], request, out);
for (Table.Cell header : table.getHeadersFromNames(displayHeaders)) {
pad(header, width[col], request, out);
out.append(" ");
}
col++;
}
out.append("\n");
}
for (List<Table.Cell> row : table.getRows()) {
for (int i = 0; i < width.length; i++) {
String headerName = table.getHeaders().get(i).value.toString();
if (displayHeaders.contains(headerName)) {
pad(row.get(i), width[i], request, out);
for (int row = 0; row < table.getRows().size(); row++) {
for (String header : displayHeaders) {
pad(table.getAsMap().get(header).get(row), width[displayHeaders.indexOf(header)], request, out);
out.append(" ");
}
}
out.append("\n");
}
return new StringRestResponse(RestStatus.OK, out.toString());
}
private static Set<String> buildDisplayHeaders(Table table, RestRequest request) {
private static List<String> buildDisplayHeaders(Table table, RestRequest request) {
String pHeaders = request.param("headers");
Set<String> display;
List<String> display = new ArrayList<String>();
if (pHeaders != null) {
display = Strings.commaDelimitedListToSet(pHeaders);
for (String possibility : Arrays.asList(Strings.splitStringByCommaToArray(pHeaders))) {
if (table.getAsMap().containsKey(possibility)) {
display.add(possibility);
}
}
} else {
display = new HashSet<String>();
for (Table.Cell cell : table.getHeaders()) {
String d = cell.attr.get("default");
if (Booleans.parseBoolean(d, true)) {
@ -145,27 +140,31 @@ public class RestTable {
return width;
}
private static int[] buildWidths(Table table, RestRequest request, boolean verbose) {
int[] width = new int[table.getHeaders().size()];
private static int[] buildWidths(Table table, RestRequest request, boolean verbose, List<String> headers) {
int[] width = new int[headers.size()];
int i;
if (verbose) {
for (int col = 0; col < width.length; col++) {
String v = renderValue(request, table.getHeaders().get(col).value);
int vWidth = v == null ? 0 : v.length();
if (width[col] < vWidth) {
width[col] = vWidth;
i = 0;
for (String hdr : headers) {
int vWidth = hdr.length();
if (width[i] < vWidth) {
width[i] = vWidth;
}
i++;
}
}
for (List<Table.Cell> row : table.getRows()) {
for (int col = 0; col < width.length; col++) {
String v = renderValue(request, row.get(col).value);
i = 0;
for (String hdr : headers) {
for (Table.Cell cell : table.getAsMap().get(hdr)) {
String v = renderValue(request, cell.value);
int vWidth = v == null ? 0 : v.length();
if (width[col] < vWidth) {
width[col] = vWidth;
if (width[i] < vWidth) {
width[i] = vWidth;
}
}
i++;
}
return width;
}