Java API: Expose source as Map (in GetResponse, SearchHit), allow to index a Map, closes #58.

This commit is contained in:
kimchy 2010-03-11 16:39:30 +02:00
parent 4b04db9030
commit 86c3a406c6
7 changed files with 120 additions and 4 deletions

View File

@ -0,0 +1,36 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search licenses this
* file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch;
/**
* A generic exception indicating failure to generate.
*
* @author kimchy (shay.banon)
*/
public class ElasticSearchGenerationException extends ElasticSearchException {
public ElasticSearchGenerationException(String msg) {
super(msg);
}
public ElasticSearchGenerationException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -19,6 +19,7 @@
package org.elasticsearch.action.get;
import org.elasticsearch.ElasticSearchParseException;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.util.Unicode;
import org.elasticsearch.util.io.Streamable;
@ -26,6 +27,9 @@ import org.elasticsearch.util.io.Streamable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Map;
import static org.elasticsearch.util.json.Jackson.*;
/**
* The response of a get action.
@ -96,6 +100,20 @@ public class GetResponse implements ActionResponse, Streamable {
return Unicode.fromBytes(source);
}
/**
* The source of the document (As a map).
*/
public Map<String, Object> sourceAsMap() throws ElasticSearchParseException {
if (!exists()) {
return null;
}
try {
return defaultObjectMapper().readValue(source, 0, source.length, Map.class);
} catch (Exception e) {
throw new ElasticSearchParseException("Failed to parse source to map", e);
}
}
@Override public void readFrom(DataInput in) throws IOException, ClassNotFoundException {
index = in.readUTF();
type = in.readUTF();

View File

@ -19,19 +19,23 @@
package org.elasticsearch.action.index;
import org.elasticsearch.ElasticSearchGenerationException;
import org.elasticsearch.ElasticSearchIllegalArgumentException;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.support.replication.ShardReplicationOperationRequest;
import org.elasticsearch.util.Required;
import org.elasticsearch.util.TimeValue;
import org.elasticsearch.util.Unicode;
import org.elasticsearch.util.io.FastByteArrayOutputStream;
import org.elasticsearch.util.json.JsonBuilder;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Map;
import static org.elasticsearch.action.Actions.*;
import static org.elasticsearch.util.json.Jackson.*;
/**
* Index request to index a typed JSON document into a specific index and make it searchable. Best
@ -190,6 +194,22 @@ public class IndexRequest extends ShardReplicationOperationRequest {
return source;
}
/**
* Writes the JSON as a {@link Map}.
*
* @param source The map to index
*/
@Required public IndexRequest source(Map source) throws ElasticSearchGenerationException {
FastByteArrayOutputStream os = FastByteArrayOutputStream.Cached.cached();
try {
defaultObjectMapper().writeValue(os, source);
} catch (IOException e) {
throw new ElasticSearchGenerationException("Failed to generate [" + source + "]", e);
}
this.source = os.copiedByteArray();
return this;
}
/**
* Sets the JSON source to index.
*

View File

@ -20,6 +20,7 @@
package org.elasticsearch.search;
import org.apache.lucene.search.Explanation;
import org.elasticsearch.ElasticSearchParseException;
import org.elasticsearch.util.io.Streamable;
import org.elasticsearch.util.json.ToJson;
@ -58,6 +59,11 @@ public interface SearchHit extends Streamable, ToJson, Iterable<SearchHitField>
*/
String sourceAsString();
/**
* The source of the document as a map (can be <tt>null</tt>).
*/
Map<String, Object> sourceAsMap() throws ElasticSearchParseException;
/**
* If enabled, the explanation of the search hit.
*/

View File

@ -21,6 +21,7 @@ package org.elasticsearch.search.internal;
import com.google.common.collect.ImmutableMap;
import org.apache.lucene.search.Explanation;
import org.elasticsearch.ElasticSearchParseException;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHitField;
import org.elasticsearch.search.SearchShardTarget;
@ -36,6 +37,7 @@ import java.util.Map;
import static org.elasticsearch.search.SearchShardTarget.*;
import static org.elasticsearch.search.internal.InternalSearchHitField.*;
import static org.elasticsearch.util.json.Jackson.*;
import static org.elasticsearch.util.lucene.Lucene.*;
/**
@ -89,6 +91,17 @@ public class InternalSearchHit implements SearchHit {
return Unicode.fromBytes(source);
}
@Override public Map<String, Object> sourceAsMap() throws ElasticSearchParseException {
if (source == null) {
return null;
}
try {
return defaultObjectMapper().readValue(source, 0, source.length, Map.class);
} catch (Exception e) {
throw new ElasticSearchParseException("Failed to parse source to map", e);
}
}
@Override public Iterator<SearchHitField> iterator() {
return fields.values().iterator();
}

View File

@ -31,6 +31,27 @@ import java.util.Arrays;
*/
public class FastByteArrayOutputStream extends OutputStream {
/**
* A thread local based cache of {@link FastByteArrayOutputStream}.
*/
public static class Cached {
private static final ThreadLocal<FastByteArrayOutputStream> cache = new ThreadLocal<FastByteArrayOutputStream>() {
@Override protected FastByteArrayOutputStream initialValue() {
return new FastByteArrayOutputStream();
}
};
/**
* Returns the cached thread local byte stream, with its internal stream cleared.
*/
public static FastByteArrayOutputStream cached() {
FastByteArrayOutputStream os = cache.get();
os.reset();
return os;
}
}
/**
* The buffer where data is stored.
*/
@ -82,15 +103,14 @@ public class FastByteArrayOutputStream extends OutputStream {
* Writes <code>len</code> bytes from the specified byte array
* starting at offset <code>off</code> to this byte array output stream.
*
* <b>NO checks for bounds, parameters must be ok!</b>
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
*/
public void write(byte b[], int off, int len) {
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
if (len == 0) {
return;
}
int newcount = count + len;

View File

@ -37,6 +37,8 @@ import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.Map;
import static org.elasticsearch.client.Requests.*;
import static org.elasticsearch.index.query.json.JsonQueryBuilders.*;
import static org.hamcrest.MatcherAssert.*;
@ -101,6 +103,7 @@ public class DocumentActionsTests extends AbstractServersTests {
for (int i = 0; i < 5; i++) {
getResult = client1.get(getRequest("test").type("type1").id("1").threadedOperation(false)).actionGet();
assertThat("cycle #" + i, getResult.sourceAsString(), equalTo(source("1", "test")));
assertThat("cycle(map) #" + i, (String) ((Map) getResult.sourceAsMap().get("type1")).get("name"), equalTo("test"));
getResult = client1.get(getRequest("test").type("type1").id("1").threadedOperation(true)).actionGet();
assertThat("cycle #" + i, getResult.sourceAsString(), equalTo(source("1", "test")));
}