All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.redkalex.source.search.OpenSearchSource Maven / Gradle / Ivy

There is a newer version: 2.7.7
Show newest version
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.redkalex.source.search;

import java.io.Serializable;
import java.lang.reflect.Type;
import java.net.*;
import java.net.http.*;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.IntFunction;
import java.util.logging.*;
import java.util.stream.*;
import org.redkale.annotation.AutoLoad;
import org.redkale.annotation.ResourceChanged;
import org.redkale.annotation.ResourceType;
import org.redkale.convert.json.*;
import org.redkale.inject.Resourcable;
import org.redkale.inject.ResourceEvent;
import org.redkale.persistence.Entity;
import org.redkale.service.*;
import org.redkale.source.*;
import static org.redkale.source.DataSources.*;
import org.redkale.util.*;

/**
 * ElasticSearch实现 
* * @author zhangjx * @since 2.4.0 */ @Local @AutoLoad(false) @SuppressWarnings("unchecked") @ResourceType(SearchSource.class) public final class OpenSearchSource extends AbstractService implements SearchSource, AutoCloseable, Resourcable { protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); protected final IntFunction serialArrayFunc = Utility.serialArrayFunc(); // key: table, 不能是class,因为存在分表的情况 protected final ConcurrentHashMap checkedIndexClasses = new ConcurrentHashMap(); protected Properties confProps; protected String name; protected URI[] uris; protected HttpClient httpClient; @Override public void init(AnyValue config) { super.init(config); Properties props = new Properties(); config.forEach((k, v) -> props.put(k, decryptProperty(k, v))); initFromProperties(props); } protected void initFromProperties(Properties props) { ProxySelector proxySelector = null; Authenticator authenticator = null; List us = new ArrayList<>(); String url = props.getProperty(DATA_SOURCE_URL); if (url.startsWith("search://")) { url = url.replace("search://", "http://"); } else if (url.startsWith("searchs://")) { url = url.replace("searchs://", "https://"); } for (String str : url.split(";")) { if (str.trim().isEmpty()) { continue; } us.add(URI.create(str.trim())); } String proxyAddr = props.getProperty(DATA_SOURCE_PROXY_ADDRESS); if (proxyAddr != null && !proxyAddr.isEmpty() && proxyAddr.contains(":") && "true".equalsIgnoreCase(props.getProperty(DATA_SOURCE_PROXY_ENABLE, "true"))) { String proxyType = props.getProperty(DATA_SOURCE_PROXY_TYPE, "HTTP").toUpperCase(); int pos = proxyAddr.indexOf(':'); SocketAddress addr = new InetSocketAddress(proxyAddr.substring(0, pos), Integer.parseInt(proxyAddr.substring(pos + 1))); proxySelector = SimpleProxySelector.create(new Proxy(Proxy.Type.valueOf(proxyType), addr)); } String proxyUser = props.getProperty(DATA_SOURCE_PROXY_USER); if (proxyUser != null && !proxyUser.isEmpty()) { char[] proxyPassword = props.getProperty(DATA_SOURCE_PROXY_PASSWORD, "").toCharArray(); authenticator = new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(proxyUser, proxyPassword); } }; } HttpClient.Builder builder = HttpClient.newBuilder(); if (proxySelector != null) { builder = builder.proxy(proxySelector); } if (authenticator != null) { builder = builder.authenticator(authenticator); } HttpClient c = builder.build(); this.uris = us.toArray(new URI[us.size()]); this.httpClient = c; this.confProps = props; } @ResourceChanged public void onResourceChange(ResourceEvent[] events) { if (Utility.isEmpty(events)) { return; } StringBuilder sb = new StringBuilder(); Properties newProps = new Properties(); newProps.putAll(this.confProps); for (ResourceEvent event : events) { // 可能需要解密 String newValue = decryptProperty(event.name(), event.newValue().toString()); newProps.put(event.name(), newValue); sb.append("DataSource(name=") .append(resourceName()) .append(") change '") .append(event.name()) .append("' to '") .append(event.coverNewValue()) .append("'\r\n"); } initFromProperties(newProps); if (sb.length() > 0) { logger.log(Level.INFO, sb.toString()); } } // 解密可能存在的加密字段, 可重载 protected String decryptProperty(String key, String value) { return value; } @Override public void destroy(AnyValue config) { super.destroy(config); } @Override public void close() throws Exception {} @Override public String toString() { if (confProps == null) { return getClass().getSimpleName() + "{}"; // compileMode模式下会为null } return getClass().getSimpleName() + "{url = " + confProps.getProperty(DATA_SOURCE_URL) + "}"; } @Override @Local public void compile(Class clazz) { SearchInfo.compile(clazz, this); JsonFactory.root().findDecoder(TypeToken.createParameterizedType(null, FindResult.class, clazz)); JsonFactory.root().findDecoder(TypeToken.createParameterizedType(null, SearchResult.class, clazz)); } @Override public String getType() { return "search"; } @Override public String resourceName() { return name; } // 检查对象是否都是同一个Entity类 protected void checkEntity(String action, T... entitys) { Class clazz = null; for (T val : entitys) { if (clazz == null) { clazz = val.getClass(); if (clazz.getAnnotation(Entity.class) == null) { throw new SourceException("Entity Class " + clazz + " must be on Annotation @Entity"); } } else if (clazz != val.getClass()) { throw new SourceException("DataSource." + action + " must the same Class Entity, but diff is " + clazz + " and " + val.getClass()); } } } protected CompletableFuture> deleteAsync(CharSequence path) { HttpRequest.Builder builder = HttpRequest.newBuilder(URI.create(uris[0].toString() + path)) .timeout(Duration.ofMillis(10_000)) .header("Content-Type", "application/json"); return httpClient .sendAsync(builder.DELETE().build(), HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)) .thenApply(resp -> { if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, path + " delete --> " + resp.body()); } return new RetResult(resp.body()).retcode(resp.statusCode()); }); } protected CompletableFuture> getAsync(CharSequence path) { HttpRequest.Builder builder = HttpRequest.newBuilder(URI.create(uris[0].toString() + path)) .timeout(Duration.ofMillis(10_000)) .header("Content-Type", "application/json"); return httpClient .sendAsync(builder.GET().build(), HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)) .thenApply(resp -> { if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, path + " get --> " + resp.body()); } return new RetResult(resp.body()).retcode(resp.statusCode()); }); } protected CompletableFuture> postAsync( CharSequence path, SearchInfo info, SearchRequest body) { return postAsync(path, convertSearchRequest(info, body)); } protected CompletableFuture> postAsync( CharSequence path, SearchInfo info, UpdatePart body) { return postAsync(path, info.getConvert().convertToBytes(body)); } protected CompletableFuture> postEntityAsync( CharSequence path, SearchInfo info, T entity) { return postAsync(path, info.getConvert().convertToBytes(entity)); } protected CompletableFuture> postAsync(CharSequence path, byte[] body) { HttpRequest.Builder builder = HttpRequest.newBuilder(URI.create(uris[0].toString() + path)) .timeout(Duration.ofMillis(10_000)) .header("Content-Type", "application/json"); HttpRequest.BodyPublisher publisher = body == null ? HttpRequest.BodyPublishers.noBody() : HttpRequest.BodyPublishers.ofByteArray(body); return httpClient .sendAsync(builder.POST(publisher).build(), HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)) .thenApply(resp -> { // SearchSource可能作为logging输出源,故此insert不能打印日志 // if (finest) logger.log(Level.FINEST, path + " post: " + (body == null ? null : new String(body, // StandardCharsets.UTF_8)) + " --> " + resp.body()); return new RetResult(resp.body()).retcode(resp.statusCode()); }); } protected CompletableFuture> putAsync( CharSequence path, SearchInfo info, Map map) { HttpRequest.Builder builder = HttpRequest.newBuilder(URI.create(uris[0].toString() + path)) .timeout(Duration.ofMillis(10_000)) .header("Content-Type", "application/json"); return httpClient .sendAsync( builder.PUT(HttpRequest.BodyPublishers.ofByteArray( info.getConvert().convertToBytes(map))) .build(), HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)) .thenApply(resp -> { // SearchSource可能作为logging输出源,故此insert不能打印日志 // if (finest) logger.log(Level.FINEST, path + " put: " + info.getConvert().convertTo(map) + " --> " // + resp.body()); return new RetResult(resp.body()).retcode(resp.statusCode()); }); } protected CompletableFuture> bulkAsync(CharSequence path, CharSequence body) { HttpRequest.Builder builder = HttpRequest.newBuilder(URI.create(uris[0].toString() + path)) .timeout(Duration.ofMillis(10_000)) .header("Content-Type", "application/x-ndjson"); return httpClient .sendAsync( builder.POST(HttpRequest.BodyPublishers.ofString(body.toString())) .build(), HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)) .thenApply(resp -> { // SearchSource可能作为logging输出源,故此insert不能打印日志 // if (finest) logger.log(Level.FINEST, path + " bulk: " + body + " --> " + resp.body()); return new RetResult(resp.body()).retcode(resp.statusCode()); }); } protected CharSequence getQueryTable(SearchInfo info, FilterNode node) { if (node == null) { return info.getTable(node); } SearchQuery bean = (SearchQuery) node.findValue(SearchQuery.SEARCH_FILTER_NAME); if (bean == null || bean.searchClasses() == null) { return info.getTable(node); } StringBuilder sb = new StringBuilder(); for (Class clazz : bean.searchClasses()) { if (clazz == null) { continue; } if (sb.length() > 0) { sb.append(','); } sb.append(SearchInfo.load(clazz).getTable(node)); } return sb.length() > 0 ? sb : info.getTable(node); } protected SearchRequest createSearchRequest( SearchInfo info, SelectColumn selects, Flipper flipper, FilterNode node) { if (flipper == null && node == null) { return SearchRequest.createMatchAll(); } return new SearchRequest().flipper(flipper).filterNode(info, node); } protected byte[] convertSearchRequest(final SearchInfo info, SearchRequest bean) { if (bean == null) { return null; } return info.getConvert().convertToBytes(bean); } protected SearchInfo loadSearchInfo(Class clazz) { return SearchInfo.load(clazz); } protected void checkIndexSync(final SearchInfo info, String table0) { if (info.isVirtual()) { return; } String table = table0 == null ? info.getOriginTable() : table0; checkedIndexClasses.computeIfAbsent(table, c -> { final StringBuilder path = new StringBuilder().append('/').append(table).append("/_mapping"); CompletableFuture future = getAsync(path).thenCompose(resp -> { if (resp.getRetcode() == 404) { // 还没有表结构 return putAsync("/" + table, info, info.createIndexMap()) .thenApply(resp2 -> resp2.getRetcode() != 200 ? null : resp); } if (resp.getRetcode() != 200) { return null; } Map rs = JsonConvert.root().convertFrom(SearchMapping.MAPPING_MAP_TYPE, resp.getResult()); SearchMapping sm = rs == null ? null : rs.get(table); if (sm == null || sm.mappings == null || !sm.mappings.equal(info.getMappingTypes())) { return updateMappingAsync(info.getType(), table) .thenCompose(v -> v == 1 ? CompletableFuture.completedFuture(1) : null); } return CompletableFuture.completedFuture(1); }); return future == null ? null : future.join(); }); } protected CompletableFuture insertOneAsync(final SearchInfo info, T entity) { final StringBuilder path = new StringBuilder() .append('/') .append(info.getTable(entity)) .append("/_create/") .append(info.getPrimary().get(entity)); return postEntityAsync(path, info, entity).thenApply(resp -> { if (resp.getRetcode() != 200 && resp.getRetcode() != 201) { throw new SourceException( "insert response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { ActionResult rs = info.getConvert().convertFrom(ActionResult.class, resp.getResult()); return rs == null || rs._shards == null ? 0 : rs._shards.successful; } }); } @Override public int batch(final DataBatch batch) { return batchAsync(batch).join(); } @Override public CompletableFuture batchAsync(final DataBatch batch) { throw new UnsupportedOperationException("Not supported yet."); } @Override public int insert(T... entitys) { return insertAsync(entitys).join(); } @Override public CompletableFuture insertAsync(T... entitys) { checkEntity("insert", entitys); final SearchInfo info = loadSearchInfo(entitys[0].getClass()); if (entitys.length == 1) { return insertOneAsync(info, entitys[0]); } final Attribute primary = info.getPrimary(); final Map tables = new LinkedHashMap<>(); for (T entity : entitys) { String table = info.getTable(entity); StringBuilder sb = tables.computeIfAbsent(table, t -> new StringBuilder()); sb.append("{\"create\":{\"_id\":\"") .append(primary.get(entity)) .append("\"}}\n") .append(info.getConvert().convertTo(entity)) .append('\n'); } final List> futures = new ArrayList<>(tables.size()); tables.forEach((table, sb) -> { checkIndexSync(info, table); final StringBuilder path = new StringBuilder().append('/').append(table).append("/_bulk"); futures.add(bulkAsync(path, sb).thenApply(resp -> { if (resp.getRetcode() != 200) { throw new SourceException( "insert response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { BulkResult rs = JsonConvert.root().convertFrom(BulkResult.class, resp.getResult()); return rs == null ? -1 : rs.successCount(); } })); }); if (futures.size() == 1) { return futures.get(0); } return Utility.allOfFutures(futures).thenApply(list -> { int count = 0; for (Integer c : list) { if (c < 0) { return c; // 存在失败的直接返回,已成功的暂时无法进行回滚 } count += c; } return count; }); } protected CompletableFuture deleteOneAsync(final SearchInfo info, Class clazz, Serializable pk) { final StringBuilder path = new StringBuilder() .append('/') .append(info.getTable(pk)) .append("/_doc/") .append(pk); return deleteAsync(path).thenApply(resp -> { if (resp.getRetcode() == 404) { return 0; } if (resp.getRetcode() != 200) { throw new SourceException( "delete response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { ActionResult rs = JsonConvert.root().convertFrom(ActionResult.class, resp.getResult()); return rs == null || rs._shards == null ? -1 : rs._shards.successful; } }); } @Override public int delete(T... entitys) { return deleteAsync(entitys).join(); } @Override public CompletableFuture deleteAsync(T... entitys) { checkEntity("delete", entitys); final SearchInfo info = loadSearchInfo(entitys[0].getClass()); final Attribute primary = info.getPrimary(); if (entitys.length == 1) { return deleteOneAsync(info, (Class) entitys[0].getClass(), primary.get(entitys[0])); } final Map tables = new LinkedHashMap<>(); for (T entity : entitys) { String table = info.getTable(entity); StringBuilder sb = tables.computeIfAbsent(table, t -> new StringBuilder()); sb.append("{\"delete\":{\"_id\":\"").append(primary.get(entity)).append("\"}}\n"); } final List> futures = new ArrayList<>(tables.size()); tables.forEach((table, sb) -> { checkIndexSync(info, table); final StringBuilder path = new StringBuilder().append('/').append(table).append("/_bulk"); futures.add(bulkAsync(path, sb).thenApply(resp -> { if (resp.getRetcode() == 404) { return 0; } if (resp.getRetcode() != 200) { throw new SourceException( "delete response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { BulkResult rs = JsonConvert.root().convertFrom(BulkResult.class, resp.getResult()); return rs == null ? -1 : rs.successCount(); } })); }); if (futures.size() == 1) { return futures.get(0); } return Utility.allOfFutures(futures).thenApply(list -> { int count = 0; for (Integer c : list) { if (c < 0) { return c; // 存在失败的直接返回,已成功的暂时无法进行回滚 } count += c; } return count; }); } @Override public int delete(Class clazz, Serializable... pks) { return deleteAsync(clazz, pks).join(); } @Override public CompletableFuture deleteAsync(Class clazz, Serializable... pks) { final SearchInfo info = loadSearchInfo(clazz); if (pks.length == 1) { return deleteOneAsync(info, clazz, pks[0]); } final Map tables = new LinkedHashMap<>(); for (Serializable pk : pks) { String table = info.getTable(pk); StringBuilder sb = tables.computeIfAbsent(table, t -> new StringBuilder()); sb.append("{\"delete\":{\"_id\":\"").append(pk).append("\"}}\n"); } final List> futures = new ArrayList<>(tables.size()); tables.forEach((table, sb) -> { checkIndexSync(info, table); final StringBuilder path = new StringBuilder().append('/').append(table).append("/_bulk"); futures.add(bulkAsync(path, sb).thenApply(resp -> { if (resp.getRetcode() == 404) { return 0; } if (resp.getRetcode() != 200) { throw new SourceException( "delete response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { BulkResult rs = JsonConvert.root().convertFrom(BulkResult.class, resp.getResult()); return rs == null ? -1 : rs.successCount(); } })); }); if (futures.size() == 1) { return futures.get(0); } return Utility.allOfFutures(futures).thenApply(list -> { int count = 0; for (Integer c : list) { if (c < 0) { return c; // 存在失败的直接返回,已成功的暂时无法进行回滚 } count += c; } return count; }); } @Override public int delete(Class clazz, FilterNode node) { return deleteAsync(clazz, (Flipper) null, node).join(); } @Override public CompletableFuture deleteAsync(Class clazz, FilterNode node) { return deleteAsync(clazz, (Flipper) null, node); } @Override public int delete(Class clazz, Flipper flipper, FilterNode node) { return deleteAsync(clazz, flipper, node).join(); } @Override public CompletableFuture deleteAsync(Class clazz, Flipper flipper, FilterNode node) { final SearchInfo info = loadSearchInfo(clazz); final StringBuilder path = new StringBuilder() .append('/') .append(getQueryTable(info, node)) .append("/_delete_by_query"); return postAsync(path, info, createSearchRequest(info, null, flipper, node)) .thenApply(resp -> { if (resp.getRetcode() == 404) { return 0; } if (resp.getRetcode() != 200) { throw new SourceException( "delete response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { ActionResult rs = JsonConvert.root().convertFrom(ActionResult.class, resp.getResult()); return rs == null || rs._shards == null ? -1 : rs._shards.successful; } }); } @Override public int clearTable(Class clazz) { return clearTableAsync(clazz, (FilterNode) null).join(); } @Override public CompletableFuture clearTableAsync(Class clazz) { return clearTableAsync(clazz, (FilterNode) null); } @Override public int clearTable(Class clazz, FilterNode node) { return clearTableAsync(clazz, node).join(); } @Override public CompletableFuture clearTableAsync(Class clazz, FilterNode node) { // final SearchInfo info = loadSearchInfo(clazz); // final String path = "/" + info.getTable() + "/_delete_by_query"; // // //{"took":24,"timed_out":false,"total":3,"deleted":3,"batches":1,"version_conflicts":0,"noops":0,"retries":{"bulk":0,"search":0},"throttled_millis":0,"requests_per_second":-1,"throttled_until_millis":0,"failures":[]} // return postAsync(path, HttpRequest.BodyPublishers.ofByteArray(BYTES_QUERY_MATCH_ALL)).thenApply(resp // -> { // if (resp.getRetcode() != 200) { // throw new SourceException("clearTable response code = " + resp.getRetcode() + ", body = " + // resp.getResult()); // } else { // ActionResult rs = JsonConvert.root().convertFrom(ActionResult.class, resp.getResult()); // return rs == null || rs._shards == null ? -1 : rs._shards.successful; // } // }); final SearchInfo info = loadSearchInfo(clazz); final StringBuilder path = new StringBuilder().append("/").append(getQueryTable(info, node)); return deleteAsync(path).thenApply(resp -> { if (resp.getRetcode() == 404) { return 0; } if (resp.getRetcode() != 200) { throw new SourceException( "clearTable response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { // {"acknowledged" : true} Map rs = JsonConvert.root().convertFrom(JsonConvert.TYPE_MAP_STRING_STRING, resp.getResult()); return rs == null || !"true".equals(rs.get("acknowledged")) ? -1 : 1; } }); } @Override public int createTable(final Class clazz, final Serializable pk) { return createTableAsync(clazz, pk).join(); } @Override public CompletableFuture createTableAsync(final Class clazz, final Serializable pk) { return CompletableFuture.completedFuture(0); } @Override public int dropTable(Class clazz) { return dropTableAsync(clazz, (FilterNode) null).join(); } @Override public CompletableFuture dropTableAsync(Class clazz) { return dropTableAsync(clazz, (FilterNode) null); } @Override public int dropTable(Class clazz, FilterNode node) { return dropTableAsync(clazz, node).join(); } @Override public CompletableFuture dropTableAsync(Class clazz, FilterNode node) { final SearchInfo info = loadSearchInfo(clazz); final StringBuilder path = new StringBuilder().append('/').append(getQueryTable(info, node)); return deleteAsync(path).thenApply(resp -> { if (resp.getRetcode() == 404) { return 0; } if (resp.getRetcode() != 200) { throw new SourceException( "dropTable response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { // {"acknowledged" : true} checkedIndexClasses.remove(clazz); Map rs = JsonConvert.root().convertFrom(JsonConvert.TYPE_MAP_STRING_STRING, resp.getResult()); return rs == null || !"true".equals(rs.get("acknowledged")) ? -1 : 1; } }); } protected CompletableFuture updateOneAsync(final SearchInfo info, T entity) { final StringBuilder path = new StringBuilder() .append('/') .append(info.getTable(entity)) .append('/') .append(info.getPrimary().get(entity)) .append("/_update"); return postEntityAsync(path, info, entity).thenApply(resp -> { if (resp.getRetcode() == 404) { return 0; } if (resp.getRetcode() != 200) { throw new SourceException( "update response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { ActionResult rs = JsonConvert.root().convertFrom(ActionResult.class, resp.getResult()); return rs == null || rs._shards == null ? -1 : rs._shards.successful; } }); } @Override public int update(T... entitys) { return updateAsync(entitys).join(); } @Override public CompletableFuture updateAsync(T... entitys) { checkEntity("update", entitys); final SearchInfo info = loadSearchInfo(entitys[0].getClass()); if (entitys.length == 1) { return updateOneAsync(info, entitys[0]); } final Attribute primary = info.getPrimary(); final Map tables = new LinkedHashMap<>(); for (T entity : entitys) { String table = info.getTable(entity); StringBuilder sb = tables.computeIfAbsent(table, t -> new StringBuilder()); sb.append("{\"update\":{\"_id\":\"") .append(primary.get(entity)) .append("\"}}\n") .append(info.getConvert().convertTo(entity)) .append('\n'); } final List> futures = new ArrayList<>(tables.size()); tables.forEach((table, sb) -> { final StringBuilder path = new StringBuilder().append('/').append(table).append("/_bulk"); futures.add(bulkAsync(path, sb).thenApply(resp -> { if (resp.getRetcode() == 404) { return 0; } if (resp.getRetcode() != 200) { throw new SourceException( "update response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { BulkResult rs = JsonConvert.root().convertFrom(BulkResult.class, resp.getResult()); return rs == null ? -1 : rs.successCount(); } })); }); if (futures.size() == 1) { return futures.get(0); } return Utility.allOfFutures(futures).thenApply(list -> { int count = 0; for (Integer c : list) { if (c < 0) { return c; // 存在失败的直接返回,已成功的暂时无法进行回滚 } count += c; } return count; }); } @Override public int updateColumn(Class clazz, Serializable pk, String column, Serializable value) { return updateColumnAsync(clazz, pk, column, value).join(); } @Override public CompletableFuture updateColumnAsync( Class clazz, Serializable pk, String column, Serializable value) { final SearchInfo info = loadSearchInfo(clazz); final StringBuilder path = new StringBuilder() .append('/') .append(info.getTable(pk)) .append('/') .append(pk) .append("/_update"); return postAsync(path, info, new UpdatePart(info, column, value)).thenApply(resp -> { if (resp.getRetcode() == 404) { return 0; } if (resp.getRetcode() != 200) { throw new SourceException( "update response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { ActionResult rs = JsonConvert.root().convertFrom(ActionResult.class, resp.getResult()); return rs == null || rs._shards == null ? -1 : rs._shards.successful; } }); } @Override public int updateColumn(Class clazz, String column, Serializable value, FilterNode node) { return updateColumnAsync(clazz, column, value, node).join(); } @Override public CompletableFuture updateColumnAsync( Class clazz, String column, Serializable value, FilterNode node) { final SearchInfo info = loadSearchInfo(clazz); final StringBuilder path = new StringBuilder().append('/').append(info.getTable(node)).append("/_update_by_query"); return postAsync(path, info, new UpdatePart(info, column, value)).thenApply(resp -> { if (resp.getRetcode() == 404) { return 0; } if (resp.getRetcode() != 200) { throw new SourceException( "update response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { ActionResult rs = JsonConvert.root().convertFrom(ActionResult.class, resp.getResult()); return rs == null || rs._shards == null ? -1 : rs._shards.successful; } }); } @Override public int updateColumn(Class clazz, Serializable pk, ColumnValue... values) { if (values.length == 0) { return 0; } return updateColumnAsync(clazz, pk, values).join(); } @Override public CompletableFuture updateColumnAsync(Class clazz, Serializable pk, ColumnValue... values) { if (values.length == 0) { return CompletableFuture.completedFuture(0); } final SearchInfo info = loadSearchInfo(clazz); final StringBuilder path = new StringBuilder() .append('/') .append(info.getTable(pk)) .append('/') .append(pk) .append("/_update"); return postAsync(path, info, new UpdatePart(info, values)).thenApply(resp -> { if (resp.getRetcode() == 404) { return 0; } if (resp.getRetcode() != 200) { throw new SourceException( "updateColumn response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { ActionResult rs = JsonConvert.root().convertFrom(ActionResult.class, resp.getResult()); return rs == null || rs._shards == null ? -1 : rs._shards.successful; } }); } @Override public int updateColumn(Class clazz, FilterNode node, ColumnValue... values) { return updateColumnAsync(clazz, node, (Flipper) null, values).join(); } @Override public CompletableFuture updateColumnAsync(Class clazz, FilterNode node, ColumnValue... values) { return updateColumnAsync(clazz, node, (Flipper) null, values); } @Override public int updateColumn(Class clazz, FilterNode node, Flipper flipper, ColumnValue... values) { return updateColumnAsync(clazz, node, flipper, values).join(); } @Override public CompletableFuture updateColumnAsync( Class clazz, FilterNode node, Flipper flipper, ColumnValue... values) { if (values.length == 0) { return CompletableFuture.completedFuture(0); } final SearchInfo info = loadSearchInfo(clazz); final StringBuilder path = new StringBuilder().append('/').append(info.getTable(node)).append("/_update_by_query"); SearchRequest bean = createSearchRequest(info, null, flipper, node); if (bean == null) { bean = new SearchRequest(); } bean.script = new UpdatePart(info, values).script; return postAsync(path, info, bean).thenApply(resp -> { if (resp.getRetcode() == 404) { return 0; } if (resp.getRetcode() != 200) { throw new SourceException( "updateColumn response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { ActionResult rs = JsonConvert.root().convertFrom(ActionResult.class, resp.getResult()); return rs == null || rs._shards == null ? -1 : rs._shards.successful; } }); } @Override public int updateColumn(T entity, String... columns) { if (columns.length == 0) { return 0; } return updateColumnAsync(entity, columns).join(); } @Override public CompletableFuture updateColumnAsync(T entity, String... columns) { if (columns.length == 0) { return CompletableFuture.completedFuture(0); } final SearchInfo info = loadSearchInfo(entity.getClass()); final StringBuilder path = new StringBuilder() .append('/') .append(info.getTable(entity)) .append('/') .append(info.getPrimary().get(entity)) .append("/_update"); final Map map = new LinkedHashMap<>(); for (String col : columns) { Attribute attr = info.getUpdateAttribute(col); map.put(col, attr.get(entity)); } return postAsync(path, info, new UpdatePart(info, map)).thenApply(resp -> { if (resp.getRetcode() == 404) { return 0; } if (resp.getRetcode() != 200) { throw new SourceException( "updateColumn response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { ActionResult rs = JsonConvert.root().convertFrom(ActionResult.class, resp.getResult()); return rs == null || rs._shards == null ? -1 : rs._shards.successful; } }); } @Override public int updateColumn(T entity, FilterNode node, String... columns) { return updateColumnAsync(entity, node, SelectColumn.includes(columns)).join(); } @Override public CompletableFuture updateColumnAsync(T entity, FilterNode node, String... columns) { return updateColumnAsync(entity, node, SelectColumn.includes(columns)); } @Override public int updateColumn(T entity, FilterNode node, SelectColumn selects) { return updateColumnAsync(entity, node, selects).join(); } @Override public CompletableFuture updateColumnAsync(T entity, FilterNode node, SelectColumn selects) { if (entity == null) { return CompletableFuture.completedFuture(0); } final SearchInfo info = loadSearchInfo(entity.getClass()); final StringBuilder path = new StringBuilder().append('/').append(info.getTable(node)).append("/_update_by_query"); SearchRequest bean = createSearchRequest(info, null, null, node); if (bean == null) { bean = new SearchRequest(); } bean.script = new UpdatePart(info, entity, selects); return postAsync(path, info, bean).thenApply(resp -> { if (resp.getRetcode() == 404) { return 0; } if (resp.getRetcode() != 200) { throw new SourceException( "updateColumn response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { ActionResult rs = JsonConvert.root().convertFrom(ActionResult.class, resp.getResult()); return rs == null || rs._shards == null ? -1 : rs._shards.successful; } }); } @Override public Number getNumberResult(Class entityClass, FilterFunc func, Number defVal, String column, FilterNode node) { return getNumberResultAsync(entityClass, func, defVal, column, node).join(); } @Override public CompletableFuture getNumberResultAsync( Class entityClass, FilterFunc func, Number defVal, String column, FilterNode node) { final SearchInfo info = loadSearchInfo(entityClass); final Attribute keyAttr = (Attribute) info.getAttribute(column); if (keyAttr == null) { return CompletableFuture.failedFuture( new RuntimeException("not found column " + column + " in " + entityClass)); } final StringBuilder path = new StringBuilder().append('/').append(info.getTable(node)).append("/_search?_source=false"); SearchRequest bean = createSearchRequest(info, null, null, node); SearchRequest.QueryFilterItem aggs = new SearchRequest.QueryFilterItem(); String funcesname = func == FilterFunc.COUNT ? "value_count" : (func == FilterFunc.DISTINCTCOUNT ? "cardinality" : func.name().toLowerCase()); // func_count:为BucketItem类其中的字段名 String field = column == null ? info.getPrimary().field() : column; aggs.put("func_count", Utility.ofMap(funcesname, Utility.ofMap("field", field))); bean.aggs = aggs; bean.size = 0; return postAsync(path, info, bean).thenApply(resp -> { if (resp.getRetcode() == 404) { return defVal; } if (resp.getRetcode() != 200) { throw new SourceException( "getNumberResult response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { SearchResult rs = JsonConvert.root().convertFrom(info.getSearchResultType(), resp.getResult()); if (rs == null || rs.timed_out || rs.aggregations == null) { return defVal; } SearchResult.Aggregations aggrs = (SearchResult.Aggregations) rs.aggregations.get("func_count"); if (aggrs == null) { return defVal; } Number d = aggrs.value; if (func == FilterFunc.COUNT || func == FilterFunc.DISTINCTCOUNT) { d = d.intValue(); } else if (keyAttr != null) { if (keyAttr != null && (func == FilterFunc.MIN || func == FilterFunc.MAX)) { if (keyAttr.type() == short.class) { d = d.shortValue(); } else if (keyAttr.type() == int.class || keyAttr.type() == char.class) { d = d.intValue(); } else if (keyAttr.type() == long.class) { d = d.longValue(); } else if (keyAttr.type() == float.class) { d = d.floatValue(); } } } return d; } }); } @Override public Map getNumberMap( Class entityClass, FilterNode node, FilterFuncColumn... columns) { return (Map) getNumberMapAsync(entityClass, node, columns).join(); } @Override public CompletableFuture> getNumberMapAsync( Class entityClass, FilterNode node, FilterFuncColumn... columns) { throw new UnsupportedOperationException( "Not supported yet."); // To change body of generated methods, choose Tools | Templates. } @Override public Map queryColumnMap( Class entityClass, String keyColumn, FilterFunc func, String funcColumn, FilterNode node) { return (Map) queryColumnMapAsync(entityClass, keyColumn, func, funcColumn, node) .join(); } @Override public CompletableFuture> queryColumnMapAsync( Class entityClass, String keyColumn, FilterFunc func, String funcColumn, FilterNode node) { final SearchInfo info = loadSearchInfo(entityClass); final Attribute keyAttr = (Attribute) info.getAttribute(keyColumn); final Attribute funcAttr = funcColumn == null ? null : (Attribute) info.getAttribute(funcColumn); if (keyAttr == null) { return CompletableFuture.failedFuture( new RuntimeException("not found column " + keyColumn + " in " + entityClass)); } if (funcColumn != null && funcAttr == null) { return CompletableFuture.failedFuture( new RuntimeException("not found column " + funcColumn + " in " + entityClass)); } final StringBuilder path = new StringBuilder().append('/').append(info.getTable(node)).append("/_search?_source=false"); SearchRequest bean = createSearchRequest(info, null, null, node); SearchRequest.QueryFilterItem aggs = new SearchRequest.QueryFilterItem(); String funcesname = func == FilterFunc.COUNT ? "value_count" : (func == FilterFunc.DISTINCTCOUNT ? "cardinality" : func.name().toLowerCase()); // func_count:为BucketItem类其中的字段名 String field = funcColumn == null ? info.getPrimary().field() : funcColumn; aggs.put( "key_" + keyColumn, Utility.ofMap( "terms", Utility.ofMap("field", keyColumn), "aggs", Utility.ofMap("func_count", Utility.ofMap(funcesname, Utility.ofMap("field", field))))); bean.aggs = aggs; bean.size = 0; return postAsync(path, info, bean).thenApply(resp -> { if (resp.getRetcode() == 404) { return new HashMap(); } if (resp.getRetcode() != 200) { throw new SourceException( "queryColumnMap response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { SearchResult rs = JsonConvert.root().convertFrom(info.getSearchResultType(), resp.getResult()); if (rs == null || rs.timed_out || rs.aggregations == null) { return new HashMap(); } SearchResult.Aggregations aggrs = rs.aggregations.get("key_" + keyColumn); if (aggrs == null || aggrs.buckets == null) { return new HashMap(); } final HashMap map = new HashMap(); final Type kt = keyAttr.genericType(); final JsonConvert convert = info.getConvert(); for (SearchResult.BucketItem item : aggrs.buckets) { if (item == null || item.key == null) { continue; } Number d = item.funcCount(); if (func == FilterFunc.COUNT || func == FilterFunc.DISTINCTCOUNT) { d = d.intValue(); } else if (funcAttr != null) { if (funcAttr != null && (func == FilterFunc.MIN || func == FilterFunc.MAX)) { if (funcAttr.type() == short.class) { d = d.shortValue(); } else if (funcAttr.type() == int.class || funcAttr.type() == char.class) { d = d.intValue(); } else if (funcAttr.type() == long.class) { d = d.longValue(); } else if (funcAttr.type() == float.class) { d = d.floatValue(); } } } map.put(kt == String.class ? item.key : convert.convertFrom(kt, item.key), d); } return map; } }); } @Override public Map queryColumnMap( Class entityClass, ColumnNode[] funcNodes, String groupByColumn, FilterNode node) { return (Map) queryColumnMapAsync(entityClass, funcNodes, groupByColumn, node).join(); } @Override public CompletableFuture> queryColumnMapAsync( Class entityClass, ColumnNode[] funcNodes, String groupByColumn, FilterNode node) { throw new UnsupportedOperationException( "Not supported yet."); // To change body of generated methods, choose Tools | Templates. } @Override public Map queryColumnMap( Class entityClass, ColumnNode[] funcNodes, String[] groupByColumns, FilterNode node) { return (Map) queryColumnMapAsync(entityClass, funcNodes, groupByColumns, node) .join(); } @Override public CompletableFuture> queryColumnMapAsync( Class entityClass, ColumnNode[] funcNodes, String[] groupByColumns, FilterNode node) { throw new UnsupportedOperationException( "Not supported yet."); // To change body of generated methods, choose Tools | Templates. } @Override public CompletableFuture findAsync(Class clazz, Serializable pk) { return findAsync(clazz, (SelectColumn) null, pk); } @Override public T find(Class clazz, SelectColumn selects, Serializable pk) { return findAsync(clazz, selects, pk).join(); } @Override public CompletableFuture findAsync(Class clazz, SelectColumn selects, Serializable pk) { final SearchInfo info = loadSearchInfo(clazz); final StringBuilder path = new StringBuilder() .append('/') .append(info.getTable(pk)) .append("/_doc/") .append(pk); if (selects != null) { path.append("?_source") .append(selects.isExcludable() ? "_excludes=" : "_includes=") .append(Utility.joining(selects.getColumns(), ',')); } return getAsync(path).thenApply(resp -> { if (resp.getRetcode() == 404) { return null; } if (resp.getRetcode() != 200) { throw new SourceException("find response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { FindResult rs = JsonConvert.root().convertFrom(info.getFindResultType(), resp.getResult()); return rs == null || !rs.found ? null : rs._source; } }); } @Override public T find(Class clazz, String column, Serializable colval) { return findAsync(clazz, column, colval).join(); } @Override public CompletableFuture findAsync(Class clazz, String column, Serializable colval) { final SearchInfo info = loadSearchInfo(clazz); final String table = info.getTableStrategy() == null ? info.getOriginTable() : info.getTable(FilterNodes.create(column, colval)); final StringBuilder path = new StringBuilder().append('/').append(table).append("/_search"); SearchRequest bean = new SearchRequest(); bean.query = new SearchRequest.Query(); bean.query.term = new SearchRequest.QueryFilterItem(); bean.query.term.put(column, colval); bean.size = 1; return postAsync(path, info, bean).thenApply(resp -> { if (resp.getRetcode() == 404) { return null; } if (resp.getRetcode() != 200) { throw new SourceException("find response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { SearchResult rs = JsonConvert.root().convertFrom(info.getSearchResultType(), resp.getResult()); if (rs == null || rs.timed_out || rs.hits == null) { return null; } return rs.hits.hits != null && rs.hits.hits.length == 1 ? rs.hits.hits[0]._source : null; } }); } @Override public T find(Class clazz, SelectColumn selects, FilterNode node) { return findAsync(clazz, selects, node).join(); } @Override public CompletableFuture findAsync(Class clazz, SelectColumn selects, FilterNode node) { final SearchInfo info = loadSearchInfo(clazz); final StringBuilder path = new StringBuilder().append('/').append(info.getTable(node)).append("/_search"); if (selects != null) { path.append("?_source") .append(selects.isExcludable() ? "_excludes=" : "_includes=") .append(Utility.joining(selects.getColumns(), ',')); } return postAsync(path, info, createSearchRequest(info, selects, null, node)) .thenApply(resp -> { if (resp.getRetcode() == 404) { return null; } if (resp.getRetcode() != 200) { throw new SourceException( "find response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { SearchResult rs = JsonConvert.root().convertFrom(info.getSearchResultType(), resp.getResult()); if (rs == null || rs.timed_out || rs.hits == null) { return null; } return rs.hits.hits != null && rs.hits.hits.length == 1 ? rs.hits.hits[0]._source : null; } }); } @Override public T[] finds(Class clazz, final SelectColumn selects, Serializable... pks) { return findsAsync(clazz, selects, pks).join(); } @Override public CompletableFuture findsAsync(Class clazz, final SelectColumn selects, Serializable... pks) { final SearchInfo info = loadSearchInfo(clazz); if (pks == null || pks.length == 0) { return CompletableFuture.completedFuture(info.getArrayer().apply(0)); } final Attribute primary = info.getPrimary(); return queryListAsync(info.getType(), selects, null, FilterNodes.in(primary.field(), pks)) .thenApply(list -> { T[] rs = info.getArrayer().apply(pks.length); for (int i = 0; i < rs.length; i++) { T t = null; Serializable pk = pks[i]; for (T item : list) { if (pk.equals(primary.get(item))) { t = item; break; } } rs[i] = t; } return rs; }); } @Override public List findsList(Class clazz, Stream pks) { return findsListAsync(clazz, pks).join(); } @Override public CompletableFuture> findsListAsync( final Class clazz, final Stream pks) { final SearchInfo info = loadSearchInfo(clazz); Serializable[] ids = pks.toArray(serialArrayFunc); return queryListAsync( info.getType(), null, null, FilterNodes.in(info.getPrimary().field(), ids)); } @Override public Serializable findColumn(Class clazz, String column, Serializable pk) { return findColumnAsync(clazz, column, (Serializable) null, pk).join(); } @Override public CompletableFuture findColumnAsync(Class clazz, String column, Serializable pk) { return findColumnAsync(clazz, column, (Serializable) null, pk); } @Override public Serializable findColumn(Class clazz, String column, Serializable defValue, Serializable pk) { return findColumnAsync(clazz, column, defValue, pk).join(); } @Override public CompletableFuture findColumnAsync( Class clazz, String column, Serializable defValue, Serializable pk) { return findAsync(clazz, SelectColumn.includes(column), pk).thenApply(v -> { if (v == null) { return defValue; } final SearchInfo info = loadSearchInfo(clazz); Serializable s = info.getAttribute(column).get(v); return s == null ? defValue : s; }); } @Override public Serializable findColumn(Class clazz, String column, Serializable defValue, FilterNode node) { return findColumnAsync(clazz, column, defValue, node).join(); } @Override public CompletableFuture findColumnAsync( Class clazz, String column, Serializable defValue, FilterNode node) { return findAsync(clazz, SelectColumn.includes(column), node).thenApply(v -> { if (v == null) { return defValue; } final SearchInfo info = loadSearchInfo(clazz); Serializable s = info.getAttribute(column).get(v); return s == null ? defValue : s; }); } @Override public boolean exists(Class clazz, Serializable pk) { return existsAsync(clazz, pk).join(); } @Override public CompletableFuture existsAsync(Class clazz, Serializable pk) { final SearchInfo info = loadSearchInfo(clazz); final StringBuilder path = new StringBuilder() .append('/') .append(info.getTable(pk)) .append("/_doc/") .append(pk) .append("?_source=false"); return getAsync(path).thenApply(resp -> { if (resp.getRetcode() == 404) { return false; } if (resp.getRetcode() != 200) { throw new SourceException( "exists response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { FindResult rs = JsonConvert.root().convertFrom(info.getFindResultType(), resp.getResult()); return rs != null && rs.found; } }); } @Override public boolean exists(Class clazz, FilterNode node) { return existsAsync(clazz, node).join(); } @Override public CompletableFuture existsAsync(Class clazz, FilterNode node) { final SearchInfo info = loadSearchInfo(clazz); final StringBuilder path = new StringBuilder().append('/').append(info.getTable(node)).append("/_search?_source=false"); return postAsync(path, info, createSearchRequest(info, null, null, node)) .thenApply(resp -> { if (resp.getRetcode() == 404) { return false; } if (resp.getRetcode() != 200) { throw new SourceException( "exists response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { SearchResult rs = JsonConvert.root().convertFrom(info.getSearchResultType(), resp.getResult()); if (rs == null || rs.timed_out || rs.hits == null) { return false; } return rs.hits.hits != null && rs.hits.hits.length == 1 && rs.hits.hits[0]._id != null; } }); } @Override public Set queryColumnSet( String selectedColumn, Class clazz, String column, Serializable colval) { return (Set) queryColumnSetAsync(selectedColumn, clazz, (Flipper) null, FilterNodes.create(column, colval)) .join(); } @Override public CompletableFuture> queryColumnSetAsync( String selectedColumn, Class clazz, String column, Serializable colval) { return queryColumnSetAsync(selectedColumn, clazz, (Flipper) null, FilterNodes.create(column, colval)); } @Override public Set queryColumnSet( String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { return (Set) queryColumnSetAsync(selectedColumn, clazz, flipper, node).join(); } @Override public CompletableFuture> queryColumnSetAsync( String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { final SearchInfo info = loadSearchInfo(clazz); final Attribute attr = (Attribute) info.getAttribute(selectedColumn); if (attr == null) { return CompletableFuture.failedFuture( new RuntimeException("not found column " + selectedColumn + " in " + clazz)); } final StringBuilder path = new StringBuilder() .append('/') .append(getQueryTable(info, node)) .append("/_search?_source_includes=") .append(selectedColumn); SearchRequest bean = createSearchRequest(info, null, flipper, node); SearchRequest.QueryFilterItem aggs = new SearchRequest.QueryFilterItem(); aggs.put("unique", Utility.ofMap("terms", Utility.ofMap("field", selectedColumn))); bean.aggs = aggs; bean.size = 0; // 不需要返回_source return postAsync(path, info, bean).thenApply(resp -> { if (resp.getRetcode() == 404) { return new HashSet(); } if (resp.getRetcode() != 200) { throw new SourceException("find response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { SearchResult rs = JsonConvert.root().convertFrom(info.getSearchResultType(), resp.getResult()); if (rs == null || rs.timed_out || rs.aggregations == null) { return new HashSet(); } SearchResult.Aggregations aggrs = rs.aggregations.get("unique"); if (aggrs == null) { return new HashSet(); } return aggrs.forEachCount(info.getConvert(), attr.genericType(), new HashSet()); } }); } @Override public List queryColumnList( String selectedColumn, Class clazz, String column, Serializable colval) { return (List) queryColumnListAsync(selectedColumn, clazz, column, colval).join(); } @Override public CompletableFuture> queryColumnListAsync( String selectedColumn, Class clazz, String column, Serializable colval) { return queryColumnListAsync(selectedColumn, clazz, (Flipper) null, FilterNodes.create(column, colval)); } @Override public List queryColumnList( String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { return (List) queryColumnListAsync(selectedColumn, clazz, flipper, node).join(); } @Override public CompletableFuture> queryColumnListAsync( String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { final SearchInfo info = loadSearchInfo(clazz); final Attribute attr = (Attribute) info.getAttribute(selectedColumn); if (attr == null) { return CompletableFuture.failedFuture( new RuntimeException("not found column " + selectedColumn + " in " + clazz)); } CompletableFuture> future = queryListAsync(clazz, SelectColumn.includes(selectedColumn), flipper, node); return future.thenApply(v -> v.stream().map(t -> attr.get(t)).collect(Collectors.toList())); } @Override public Sheet queryColumnSheet( String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { return (Sheet) queryColumnSheetAsync(selectedColumn, clazz, flipper, node).join(); } @Override public CompletableFuture> queryColumnSheetAsync( String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { final SearchInfo info = loadSearchInfo(clazz); final Attribute attr = (Attribute) info.getAttribute(selectedColumn); if (attr == null) { return CompletableFuture.failedFuture( new RuntimeException("not found column " + selectedColumn + " in " + clazz)); } CompletableFuture> future = querySheetAsync(clazz, SelectColumn.includes(selectedColumn), flipper, node); return future.thenApply(v -> v.isEmpty() ? (Sheet) v : new Sheet<>(v.getTotal(), v.stream().map(t -> attr.get(t)).collect(Collectors.toList()))); } @Override public Map queryMap(Class clazz, SelectColumn selects, Stream keyStream) { return queryMapAsync(clazz, selects, keyStream).join(); } @Override public CompletableFuture> queryMapAsync( Class clazz, SelectColumn selects, Stream keyStream) { if (keyStream == null) { return CompletableFuture.completedFuture(new LinkedHashMap<>()); } final SearchInfo info = loadSearchInfo(clazz); final ArrayList pks = new ArrayList<>(); keyStream.forEach(k -> pks.add(k)); final Attribute primary = info.getPrimary(); return queryListAsync(clazz, FilterNodes.create(primary.field(), pks)).thenApply((List rs) -> { Map map = new LinkedHashMap<>(); if (rs.isEmpty()) { return new LinkedHashMap<>(); } for (T item : rs) { map.put((K) primary.get(item), item); } return map; }); } @Override public Map queryMap(Class clazz, SelectColumn selects, FilterNode node) { return (Map) queryMapAsync(clazz, selects, node).join(); } @Override public CompletableFuture> queryMapAsync( Class clazz, SelectColumn selects, FilterNode node) { return queryListAsync(clazz, selects, node).thenApply((List rs) -> { final SearchInfo info = loadSearchInfo(clazz); final Attribute primary = info.getPrimary(); Map map = new LinkedHashMap<>(); if (rs.isEmpty()) { return new LinkedHashMap<>(); } for (T item : rs) { map.put((K) primary.get(item), item); } return map; }); } @Override public Set querySet(Class clazz, Flipper flipper, String column, Serializable colval) { return querySetAsync(clazz, (SelectColumn) null, flipper, FilterNodes.create(column, colval)) .join(); } @Override public CompletableFuture> querySetAsync( Class clazz, Flipper flipper, String column, Serializable colval) { return querySetAsync(clazz, (SelectColumn) null, flipper, FilterNodes.create(column, colval)); } @Override public Set querySet(Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { return querySetAsync(clazz, selects, flipper, node).join(); } @Override public CompletableFuture> querySetAsync( Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { return querySheetAsync(false, true, clazz, selects, flipper, node) .thenApply(s -> new LinkedHashSet(s.list(true))); } @Override public List queryList(Class clazz, Flipper flipper, String column, Serializable colval) { return queryListAsync(clazz, (SelectColumn) null, flipper, FilterNodes.create(column, colval)) .join(); } @Override public CompletableFuture> queryListAsync( Class clazz, Flipper flipper, String column, Serializable colval) { return queryListAsync(clazz, (SelectColumn) null, flipper, FilterNodes.create(column, colval)); } @Override public List queryList(Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { return queryListAsync(clazz, selects, flipper, node).join(); } @Override public CompletableFuture> queryListAsync( Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { return querySheetAsync(false, false, clazz, selects, flipper, node).thenApply(s -> s.list(true)); } @Override public Sheet querySheet(Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { return querySheetAsync(clazz, selects, flipper, node).join(); } @Override public CompletableFuture> querySheetAsync( Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { return querySheetAsync(true, false, clazz, selects, flipper, node); } protected CompletableFuture> querySheetAsync( boolean needtotal, boolean distinct, Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { final SearchInfo info = loadSearchInfo(clazz); final StringBuilder path = new StringBuilder() .append('/') .append(getQueryTable(info, node)) .append("/_search"); if (selects != null) { path.append("?_source") .append(selects.isExcludable() ? "_excludes=" : "_includes=") .append(Utility.joining(selects.getColumns(), ',')); } return postAsync(path, info, createSearchRequest(info, selects, flipper, node)) .thenApply(resp -> { if (resp.getRetcode() == 404) { return new Sheet(); } if (resp.getRetcode() != 200) { throw new SourceException( "find response code = " + resp.getRetcode() + ", body = " + resp.getResult()); } else { SearchResult rs = JsonConvert.root().convertFrom(info.getSearchResultType(), resp.getResult()); if (rs == null || rs.timed_out || rs.hits == null) { return new Sheet(); } HitResult hits = rs.hits; return new Sheet(hits.total.value, hits.list(info)); } }); } @Override public int updateMapping(final Class clazz, String table) { return updateMappingAsync(clazz, table).join(); } /** * * *
* *
     * {
     *   "settings": {
     *      "analysis": {
     *          "analyzer": {
     *              "html_ik_max_word": {
     *                  "type": "custom",
     *                  "tokenizer": "ik_max_word",
     *                  "char_filter": ["html_strip"]
     *              },
     *              "html_standard": {
     *                  "type": "custom",
     *                  "tokenizer": "standard",
     *                  "char_filter": ["html_strip"]
     *              }
     *          }
     *      }
     *   }
     * }
     * 
* *
* * @param T * @param clazz Class * @param table0 String * @return int */ @Override public CompletableFuture updateMappingAsync(final Class clazz, String table0) { final SearchInfo info = loadSearchInfo(clazz); String table = table0 == null ? info.getOriginTable() : table0; final StringBuilder path = new StringBuilder().append('/').append(table).append("/_mapping"); // 更新setting时,必须先关闭索引,再更新, 再打开索引。 更新setting是为了增加自定义的分词器 return postAsync("/" + table + "/_close?wait_for_active_shards=0", (byte[]) null) .thenCompose(c -> { CompletableFuture> updateFuture; if (!info.getCustomAnalyzerMap().isEmpty()) { updateFuture = putAsync( "/" + table + "/_settings", info, Utility.ofMap( "analysis", Utility.ofMap("analyzer", info.getCustomAnalyzerMap()))) .thenCompose(cv -> putAsync(path, info, Utility.ofMap("properties", info.getMappingTypes()))); } else { updateFuture = putAsync(path, info, Utility.ofMap("properties", info.getMappingTypes())); } return updateFuture.thenCompose(resp -> { if (resp.getRetcode() == 404) { return postAsync("/" + table + "/_open", (byte[]) null) .thenApply(cv -> -1); } if (resp.getRetcode() != 200) { return postAsync("/" + table + "/_open", (byte[]) null) .thenApply(cv -> { throw new SourceException("updateMapping response code = " + resp.getRetcode() + ", body = " + resp.getResult()); }); } else { // {"acknowledged":true} Map rs = JsonConvert.root() .convertFrom(JsonConvert.TYPE_MAP_STRING_STRING, resp.getResult()); int val = rs == null || !"true".equals(rs.get("acknowledged")) ? -1 : 1; return postAsync("/" + table + "/_open", (byte[]) null) .thenApply(cv -> val); } }); }); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy