package org.xbib.elasticsearch.helper.client.ingest;
import org.elasticsearch.action.search.SearchAction;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.Before;
import org.xbib.elasticsearch.helper.client.ClientBuilder;
import org.xbib.elasticsearch.helper.client.IngestTransportClient;
import org.xbib.elasticsearch.helper.client.LongAdderIngestMetric;
import org.elasticsearch.client.transport.NoNodeAvailableException;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.common.util.concurrent.EsExecutors;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.xbib.elasticsearch.NodeTestUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
public class IngestTransportClientTest extends NodeTestUtils {
private final static ESLogger logger = ESLoggerFactory.getLogger(IngestTransportClientTest.class.getSimpleName());
private final static Long MAX_ACTIONS = 100L;
private final static Long NUM_ACTIONS = 1234L;
@Before
public void startNodes() {
try {
super.startNodes();
startNode("2");
} catch (Throwable t) {
logger.error("startNodes failed", t);
}
}
@Test
public void testSingleDocIngestClient() throws IOException {
Settings settings = Settings.settingsBuilder()
.put("index.number_of_shards", 2)
.put("index.number_of_replicas", 1)
.build();
final IngestTransportClient ingest = ClientBuilder.builder()
.put(getSettings())
.put(ClientBuilder.FLUSH_INTERVAL, TimeValue.timeValueSeconds(60))
.setMetric(new LongAdderIngestMetric())
.toIngestTransportClient();
try {
ingest.newIndex("test", settings, null);
ingest.index("test", "test", "1", "{ \"name\" : \"Hello World\"}"); // single doc ingest
ingest.flushIngest();
ingest.waitForResponses(TimeValue.timeValueSeconds(30));
} catch (NoNodeAvailableException e) {
logger.warn("skipping, no node available");
} catch (InterruptedException e) {
// ignore
} finally {
logger.info("total bulk requests = {}", ingest.getMetric().getTotalIngest().getCount());
assertEquals(1, ingest.getMetric().getTotalIngest().getCount());
if (ingest.hasThrowable()) {
logger.error("error", ingest.getThrowable());
}
assertFalse(ingest.hasThrowable());
ingest.shutdown();
}
}
@Test
public void testRandomDocsIngestClient() throws Exception {
long numactions = NUM_ACTIONS;
Settings settings = Settings.settingsBuilder()
.put("index.number_of_shards", 2)
.put("index.number_of_replicas", 1)
.build();
final IngestTransportClient ingest = ClientBuilder.builder()
.put(getSettings())
.put(ClientBuilder.MAX_ACTIONS_PER_REQUEST, MAX_ACTIONS)
.put(ClientBuilder.FLUSH_INTERVAL, TimeValue.timeValueSeconds(60))
.setMetric(new LongAdderIngestMetric())
.toIngestTransportClient();
try {
ingest.newIndex("test", settings, null)
.startBulk("test", -1, 1000);
for (int i = 0; i < NUM_ACTIONS; i++) {
ingest.index("test", "test", null, "{ \"name\" : \"" + randomString(32) + "\"}");
}
ingest.flushIngest();
ingest.waitForResponses(TimeValue.timeValueSeconds(30));
} catch (NoNodeAvailableException e) {
logger.warn("skipping, no node available");
} catch (InterruptedException e) {
// ignore
} finally {
ingest.stopBulk("test");
logger.info("total requests = {}", ingest.getMetric().getTotalIngest().getCount());
assertEquals(numactions, ingest.getMetric().getTotalIngest().getCount());
if (ingest.hasThrowable()) {
logger.error("error", ingest.getThrowable());
}
assertFalse(ingest.hasThrowable());
ingest.shutdown();
}
}
@Test
public void testThreadedRandomDocsIngestClient() throws Exception {
int maxthreads = Runtime.getRuntime().availableProcessors();
long maxactions = MAX_ACTIONS;
final long maxloop = NUM_ACTIONS;
Settings settings = Settings.settingsBuilder()
.put("index.number_of_shards", 2)
.put("index.number_of_replicas", 1)
.build();
final IngestTransportClient ingest = ClientBuilder.builder()
.put(getSettings())
.put(ClientBuilder.MAX_ACTIONS_PER_REQUEST, maxactions)
.put(ClientBuilder.FLUSH_INTERVAL, TimeValue.timeValueSeconds(60))
.setMetric(new LongAdderIngestMetric())
.toIngestTransportClient();
try {
ingest.newIndex("test", settings, null)
.startBulk("test", -1, 1000);
ThreadPoolExecutor pool =
EsExecutors.newFixed("ingestclient-test", maxthreads, 30, EsExecutors.daemonThreadFactory("ingestclient-test"));
final CountDownLatch latch = new CountDownLatch(maxthreads);
for (int i = 0; i < maxthreads; i++) {
pool.execute(new Runnable() {
public void run() {
for (int i = 0; i < maxloop; i++) {
ingest.index("test", "test", null, "{ \"name\" : \"" + randomString(32) + "\"}");
}
latch.countDown();
}
});
}
logger.info("waiting for max 30 seconds...");
latch.await(30, TimeUnit.SECONDS);
logger.info("client flush ...");
ingest.flushIngest();
ingest.waitForResponses(TimeValue.timeValueSeconds(30));
logger.info("thread pool to be shut down ...");
pool.shutdown();
logger.info("thread pool shut down");
} catch (NoNodeAvailableException e) {
logger.warn("skipping, no node available");
} finally {
ingest.stopBulk("test");
assertEquals(maxthreads * maxloop, ingest.getMetric().getSucceeded().getCount());
if (ingest.hasThrowable()) {
logger.error("error", ingest.getThrowable());
}
assertFalse(ingest.hasThrowable());
ingest.refreshIndex("test");
SearchRequestBuilder searchRequestBuilder = new SearchRequestBuilder(ingest.client(), SearchAction.INSTANCE)
.setIndices("_all") // to avoid NPE
.setQuery(QueryBuilders.matchAllQuery())
.setSize(0);
assertEquals(maxthreads * maxloop,
searchRequestBuilder.execute().actionGet().getHits().getTotalHits());
ingest.shutdown();
}
}
}