Skip to content

Commit

Permalink
Merge pull request searchbox-io#520 from gilbode/update_by_query
Browse files Browse the repository at this point in the history
Update by query
  • Loading branch information
ferhatsb authored Sep 22, 2017
2 parents bb67e73 + c19aed8 commit 9021cb6
Show file tree
Hide file tree
Showing 4 changed files with 318 additions and 0 deletions.
72 changes: 72 additions & 0 deletions jest-common/src/main/java/io/searchbox/core/UpdateByQuery.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package io.searchbox.core;

import com.google.gson.Gson;
import io.searchbox.action.AbstractAction;
import io.searchbox.action.AbstractMultiTypeActionBuilder;
import java.util.Objects;

/**
* @author Lior Knaany
*/
public class UpdateByQuery extends AbstractAction<UpdateByQueryResult> {

protected UpdateByQuery(Builder builder) {
super(builder);

this.payload = builder.payload;
setURI(buildURI());
}

@Override
protected String buildURI() {
return super.buildURI() + "/_update_by_query";
}

@Override
public String getPathToResult() {
return "ok";
}

@Override
public String getRestMethodName() {
return "POST";
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode());
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (obj.getClass() != getClass()) {
return false;
}

return super.equals(obj);
}

@Override
public UpdateByQueryResult createNewElasticSearchResult(String responseBody, int statusCode, String reasonPhrase, Gson gson) {
return createNewElasticSearchResult(new UpdateByQueryResult(gson), responseBody, statusCode, reasonPhrase, gson);
}

public static class Builder extends AbstractMultiTypeActionBuilder<UpdateByQuery, Builder> {

private Object payload;

public Builder(Object payload) {this.payload = payload;}

@Override
public UpdateByQuery build() {
return new UpdateByQuery(this);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package io.searchbox.core;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import io.searchbox.client.JestResult;

/**
* Created by Lior Knaany on 12/26/16.
*/
public class UpdateByQueryResult extends JestResult {

public UpdateByQueryResult(Gson gson) {
super(gson);
}

public boolean didTimeOut() {
return (jsonObject != null && jsonObject.has("timed_out")) ? jsonObject.get("timed_out").getAsBoolean() : false;
}

public long getConflictsCount() {
return (jsonObject != null && jsonObject.has("version_conflicts")) ? jsonObject.get("version_conflicts").getAsLong() : 0L;
}

public long getMillisTaken() {
return (jsonObject != null && jsonObject.has("took")) ? jsonObject.get("took").getAsLong() : 0L;
}

public long getUpdatedCount() {
return (jsonObject != null && jsonObject.has("updated")) ? jsonObject.get("updated").getAsLong() : 0L;
}

public int getBatchCount() {
return (jsonObject != null && jsonObject.has("batches")) ? jsonObject.get("batches").getAsInt() : 0;
}

public int getRetryCount() {
return getBulkRetryCount() + getSearchRetryCount();
}

public int getBulkRetryCount() {
return (jsonObject != null && jsonObject.has("retries") && jsonObject.getAsJsonObject("retries").has("bulk")) ? jsonObject.getAsJsonObject("retries").get("bulk").getAsInt() : 0;
}

public int getSearchRetryCount() {
return (jsonObject != null && jsonObject.has("retries") && jsonObject.getAsJsonObject("retries").has("search")) ? jsonObject.getAsJsonObject("retries").get("search").getAsInt() : 0;
}

public int getNoopCount() {
return (jsonObject != null && jsonObject.has("noops")) ? jsonObject.get("noops").getAsInt() : 0;
}

public JsonArray getFailures() {
return (jsonObject != null && jsonObject.has("failures")) ? jsonObject.get("failures").getAsJsonArray() : null;
}

@Override
public String toString() {
return "Updated: " + getUpdatedCount()
+ ", conflicts: " + getConflictsCount()
+ ", time taken: " + getMillisTaken()
+ ", did time out: " + didTimeOut()
+ ", batches: " + getBatchCount()
+ ", retries: " + getRetryCount()
+ ", bulk retries: " + getBulkRetryCount()
+ ", search retries: " + getSearchRetryCount()
+ ", noops: " + getNoopCount();
}
}
86 changes: 86 additions & 0 deletions jest-common/src/test/java/io/searchbox/core/UpdateByQueryTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package io.searchbox.core;

import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;

/**
* @author Lior Knaany
*/
public class UpdateByQueryTest {

@Test
public void getURIWithoutIndexAndType() {
assertEquals("_all/_update_by_query", new UpdateByQuery.Builder(null).build().getURI());
}

@Test
public void getURIWithOnlyOneIndex() {
assertEquals("twitter/_update_by_query", new UpdateByQuery.Builder(null).addIndex("twitter").build().getURI());
}

@Test
public void getURIWithOnlyMultipleType() {
assertEquals("_all/tweet%2Cjest/_update_by_query", new UpdateByQuery.Builder(null).addType("tweet").addType("jest").build().getURI());
}

@Test
public void getURIWithOneIndexAndOneType() {
assertEquals("twitter/tweet/_update_by_query", new UpdateByQuery.Builder(null).addIndex("twitter").addType("tweet").build().getURI());
}

@Test
public void getURIWithOnlyMultipleIndex() {
assertEquals("twitter%2Csearchbox/_update_by_query",
new UpdateByQuery.Builder(null).addIndex("twitter").addIndex("searchbox").build().getURI());
}

@Test
public void getURIWithMultipleIndexAndTypes() {
assertEquals("twitter%2Csearchbox/tweet%2Cjest/_update_by_query", new UpdateByQuery.Builder(null)
.addIndex("twitter")
.addIndex("searchbox")
.addType("tweet")
.addType("jest")
.build()
.getURI());
}

@Test
public void equals() {
UpdateByQuery deleteUserKramer = new UpdateByQuery.Builder("{\"user\":\"kramer\"}")
.addIndex("twitter")
.addIndex("searchbox")
.addType("tweet")
.addType("jest")
.build();
UpdateByQuery deleteUserKramerDuplicate = new UpdateByQuery.Builder("{\"user\":\"kramer\"}")
.addIndex("twitter")
.addIndex("searchbox")
.addType("tweet")
.addType("jest")
.build();

assertEquals(deleteUserKramer, deleteUserKramerDuplicate);
}

@Test
public void equalsReturnsFalseForDifferentQueries() {
UpdateByQuery deleteUserKramer = new UpdateByQuery.Builder("{\"user\":\"kramer\"}")
.addIndex("twitter")
.addIndex("searchbox")
.addType("tweet")
.addType("jest")
.build();
UpdateByQuery deleteUserJerry = new UpdateByQuery.Builder("{\"user\":\"jerry\"}")
.addIndex("twitter")
.addIndex("searchbox")
.addType("tweet")
.addType("jest")
.build();

assertNotEquals(deleteUserKramer, deleteUserJerry);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package io.searchbox.core;

import com.google.gson.GsonBuilder;

import io.searchbox.common.AbstractIntegrationTest;
import io.searchbox.core.UpdateByQueryResult;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.ReindexPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.test.ESIntegTestCase;
import org.junit.Test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;


/**
* @author Lior Knaany
*/
@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.SUITE, numDataNodes = 1)
public class UpdateByQueryIntegrationTest extends AbstractIntegrationTest {

private static final String INDEX = "twitter";
private static final String TYPE = "tweet";

@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
final ArrayList<Class<? extends Plugin>> plugins = new ArrayList<>(super.nodePlugins());
plugins.add(ReindexPlugin.class);
return plugins;
}

@Override
protected Settings nodeSettings(int nodeOrdinal) {
final Settings.Builder builder = Settings.builder().put(super.nodeSettings(nodeOrdinal));
return builder
.put(super.nodeSettings(nodeOrdinal))
.put("script.inline", "true")
.build();
}

@Test
public void update() throws IOException, InterruptedException {

// create a tweet
assertTrue(index(INDEX, TYPE, "1", "{\"user\":\"lior\",\"num\":1}").getResult().equals(DocWriteResponse.Result.CREATED));
assertTrue(index(INDEX, TYPE, "2", "{\"user\":\"kimchy\",\"num\":2}").getResult().equals(DocWriteResponse.Result.CREATED));

refresh();
ensureSearchable(INDEX);

// run the search and update
final BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.termQuery("user", "lior"));
final String script = "ctx._source.user = ctx._source.user + '_updated';";

final String payload = jsonBuilder()
.startObject()
.field("query", queryBuilder)
.startObject("script")
.field("inline", script)
.endObject()
.endObject().string();

UpdateByQuery updateByQuery = new UpdateByQuery.Builder(payload)
.addIndex(INDEX)
.addType(TYPE)
.build();

UpdateByQueryResult result = client.execute(updateByQuery);

// Checks
assertTrue(result.getErrorMessage(), result.isSucceeded());

assertFalse(result.didTimeOut());
assertEquals(0, result.getConflictsCount());
assertTrue(result.getMillisTaken() > 0);
assertEquals(1, result.getUpdatedCount());
assertEquals(0, result.getRetryCount());
assertEquals(0, result.getBulkRetryCount());
assertEquals(0, result.getSearchRetryCount());
assertEquals(0, result.getNoopCount());
assertEquals(0, result.getFailures().size());
}

}

0 comments on commit 9021cb6

Please sign in to comment.