v2.0-beta1

进一步完善功能,测试用例,以及增加执行SQL功能
This commit is contained in:
xpc1024 2023-03-11 16:49:20 +08:00
parent 848ba0c7b5
commit 01a50faa8f
14 changed files with 207 additions and 42 deletions

View File

@ -216,4 +216,16 @@ public interface BaseEsConstants {
* keyword后缀
*/
String KEYWORD_SUFFIX = ".keyword";
/**
* 执行SQL x-pack 固定地址
*/
String SQL_ENDPOINT = "/_xpack/sql?format=json";
/**
* 执行DSL 查询固定地址
*/
String DSL_ENDPOINT = "/_search";
/**
* 查询
*/
String QUERY = "query";
}

View File

@ -100,7 +100,7 @@ public enum EsQueryTypeEnum {
/**
* 与条件必须满足但不返回得分效率更高
*/
FILTER,
AND_FILTER,
/**
* 或条件相当于MYSQL中的OR 和MP中的or嵌套用法一致
*/
@ -110,7 +110,16 @@ public enum EsQueryTypeEnum {
*/
NESTED,
/**
* 或条件仅影响紧跟其后的一个条件和MP中的拼接or用法一致
* 拼接OR,条件和MP中的拼接or用法一致
*/
OR;
OR,
/**
* 拼接NOT,非条件 表示必须不满足
*/
NOT,
/**
* 拼接filter,
*/
FILTER;
}

View File

@ -8,6 +8,28 @@ import java.io.Serializable;
* Copyright © 2021 xpc1024 All Rights Reserved
**/
public interface Join<Children> extends Serializable {
/**
* 拼接filter
*
* @return 泛型
*/
default Children filter() {
return filter(true);
}
/**
* 拼接filter
*
* @param condition 条件
* @return 泛型
*/
Children filter(boolean condition);
/**
* 拼接or
*
* @return 泛型
*/
default Children or() {
return or(true);
}
@ -19,4 +41,21 @@ public interface Join<Children> extends Serializable {
* @return 泛型
*/
Children or(boolean condition);
/**
* 拼接not
*
* @return 泛型
*/
default Children not() {
return not(true);
}
/**
* 拼接not
*
* @param condition 条件
* @return 泛型
*/
Children not(boolean condition);
}

View File

@ -39,14 +39,14 @@ public class GlobalConfig {
private boolean distributed = true;
/**
* Activate the current client's release index maximum number of retries
* 分布式环境下,平滑模式,当前客户端激活最新索引最大重试次数若数据量过大,重建索引数据迁移时间超过60*(180/60)=180分钟时,可调大此参数值,此参数值决定最大重试次数,超出此次数后仍未成功,则终止重试并记录异常日志
* 分布式环境下,平滑模式,当前客户端激活最新索引最大重试次数,若数据量过大,重建索引数据迁移时间超过4320/60=72H,可调大此参数值,此参数值决定最大重试次数,超出此次数后仍未成功,则终止重试并记录异常日志
*/
private int activeReleaseIndexMaxRetry = 60;
private int activeReleaseIndexMaxRetry = 4320;
/**
* Activate the current client's release index retry delay for a fixed time uint:second
* 分布式环境下,平滑模式,当前客户端激活最新索引最大重试次数 若数据量过大,重建索引数据迁移时间超过60*(180/60)=180分钟时,可调大此参数值 此参数值决定多久重试一次 单位:
* 分布式环境下,平滑模式,当前客户端激活最新索引重试时间间隔 若您期望最终一致性的时效性更高,可调小此值,但会牺牲一些性能
*/
private int activeReleaseIndexFixedDelay = 180;
private int activeReleaseIndexFixedDelay = 60;
/**
* es db config 数据库配置
*/
@ -61,7 +61,7 @@ public class GlobalConfig {
/**
* index prefix eg:daily_, 索引前缀 可缺省
*/
private String tablePrefix = EMPTY_STR;
private String indexPrefix = EMPTY_STR;
/**
* enable underscore to camel case default false 是否开启下划线自动转驼峰 默认关闭
*/

View File

@ -571,7 +571,19 @@ public abstract class AbstractChainWrapper<T, R, Children extends AbstractChainW
@Override
public Children or(boolean condition) {
getWrapper().exists(condition);
getWrapper().or(condition);
return typedThis;
}
@Override
public Children not(boolean condition) {
getWrapper().not(condition);
return typedThis;
}
@Override
public Children filter(boolean condition) {
getWrapper().filter(condition);
return typedThis;
}

View File

@ -158,7 +158,17 @@ public abstract class AbstractWrapper<T, R, Children extends AbstractWrapper<T,
@Override
public Children filter(boolean condition, Consumer<Children> consumer) {
return addNested(condition, FILTER, consumer);
return addNested(condition, AND_FILTER, consumer);
}
@Override
public Children filter(boolean condition) {
return addParam(condition, FILTER, null, null, null);
}
@Override
public Children not(boolean condition) {
return addParam(condition, NOT, null, null, null);
}
@Override
@ -667,8 +677,8 @@ public abstract class AbstractWrapper<T, R, Children extends AbstractWrapper<T,
param.setBoost(boost);
param.setLevel(level);
// 入队之前需要先对MP中的拼接or()特殊处理
processOr(param);
// 入队之前需要先对MP中的拼接类型特殊处理
processJoin(param);
paramQueue.add(param);
}
@ -687,8 +697,15 @@ public abstract class AbstractWrapper<T, R, Children extends AbstractWrapper<T,
param.setLevel(level);
param.setPrevQueryType(queryTypeEnum);
// 入队之前需要先对MP中的拼接or()特殊处理
processOr(param);
// 入队之前需要先对MP中的拼接类型特殊处理
processJoin(param);
// 这两种情况需要重置其prevType
if (MUST_NOT.equals(queryTypeEnum)) {
prevQueryType = MUST_NOT;
} else if (FILTER.equals(queryTypeEnum)) {
prevQueryType = FILTER;
}
paramQueue.add(param);
this.parentId = param.getId();
@ -708,16 +725,22 @@ public abstract class AbstractWrapper<T, R, Children extends AbstractWrapper<T,
/**
* 特殊处理拼接or
* 特殊处理拼接
*
* @param param 参数
*/
private void processOr(Param param) {
private void processJoin(Param param) {
if (!paramQueue.isEmpty()) {
Param prev = paramQueue.peekLast();
if (OR.equals(prev.getQueryTypeEnum())) {
// 上一节点是拼接or() 需要重置其prevQueryType类型,让其走should查询
param.setPrevQueryType(OR_SHOULD);
} else if (NOT.equals(prev.getQueryTypeEnum())) {
// 上一节点是拼接not() 需要重置其prevQueryType类型,让其走must_not查询
param.setPrevQueryType(MUST_NOT);
} else if (FILTER.equals(prev.getPrevQueryType())) {
// 上一节点是拼接filter() 需要重置其prevQueryType类型,让其走filter查询
param.setPrevQueryType(AND_FILTER);
}
}
}

View File

@ -1,6 +1,5 @@
package cn.easyes.core.core;
import cn.easyes.common.enums.MethodEnum;
import cn.easyes.core.biz.EsPageInfo;
import cn.easyes.core.biz.SAPageInfo;
import org.elasticsearch.action.search.SearchRequest;
@ -100,24 +99,30 @@ public interface BaseEsMapper<T> {
*/
Boolean refresh(String... indexNames);
/**
* 执行SQL语句
*
* @param sql 被执行的sql语句
* @return 执行结果 jsonString
*/
String executeSQL(String sql);
/**
* 执行静态dsl语句 不传索引名,默认为当前mapper对应索引
*
* @param dsl dsl语句
* @param method 请求类型 比如查询类GET 更新PUT...
* @return 执行结果 jsonString
*/
String executeDSL(String dsl, MethodEnum method);
String executeDSL(String dsl);
/**
* 执行静态dsl语句 可指定作用的索引
*
* @param dsl dsl语句
* @param method 请求类型 比如查询类GET 更新PUT...
* @param indexName 作用的索引名
* @return 执行结果 jsonString
*/
String executeDSL(String dsl, MethodEnum method, String indexName);
String executeDSL(String dsl, String indexName);
/**
* 标准查询

View File

@ -167,18 +167,26 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
@Override
@SneakyThrows
public String executeDSL(String dsl, MethodEnum method) {
String indexName = EntityInfoHelper.getEntityInfo(entityClass).getIndexName();
Request request = new Request(method.toString(), indexName);
public String executeSQL(String sql) {
Request request = new Request(MethodEnum.POST.name(), SQL_ENDPOINT);
JSONObject jsonObject = new JSONObject();
jsonObject.put(QUERY, sql);
request.setJsonEntity(jsonObject.toJSONString());
Response response = client.getLowLevelClient().performRequest(request);
return EntityUtils.toString(response.getEntity());
}
@Override
@SneakyThrows
public String executeDSL(String dsl, MethodEnum method, String indexName) {
public String executeDSL(String dsl) {
return executeDSL(dsl, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
}
@Override
@SneakyThrows
public String executeDSL(String dsl, String indexName) {
Assert.notNull(indexName, "indexName must not null");
Request request = new Request(method.toString(), indexName);
Request request = new Request(MethodEnum.GET.name(), indexName + DSL_ENDPOINT);
Response response = client.getLowLevelClient().performRequest(request);
return EntityUtils.toString(response.getEntity());
}

View File

@ -98,7 +98,9 @@ public class WrapperProcessor {
String realField;
switch (param.getQueryTypeEnum()) {
case OR:
// 渣男行为,*完就不认人了,因为拼接OR已处理过了 直接跳过
case NOT:
case FILTER:
// 渣男行为,*完就不认人了,因为拼接类型在AbstractWrapper中已处理过了 直接跳过
break;
case TERM:
realField = getRealFieldAndSuffix(param.getColumn(), fieldTypeMap, mappingColumnMap);
@ -233,7 +235,7 @@ public class WrapperProcessor {
break;
// 下面五种嵌套类型 需要对孩子节点递归处理
case AND_MUST:
case FILTER:
case AND_FILTER:
case MUST_NOT:
case OR_SHOULD:
queryBuilder = getBool(children, QueryBuilders.boolQuery(), entityInfo, null);
@ -264,12 +266,12 @@ public class WrapperProcessor {
bool.must(queryBuilder);
} else if (OR_SHOULD.equals(parentType)) {
bool.should(queryBuilder);
} else if (FILTER.equals(parentType)) {
} else if (AND_FILTER.equals(parentType)) {
bool.filter(queryBuilder);
} else if (MUST_NOT.equals(parentType)) {
bool.mustNot(queryBuilder);
} else {
// just ignore,almost never happen
// by default
bool.must(queryBuilder);
}
}

View File

@ -581,7 +581,7 @@ public class EntityInfoHelper {
GlobalConfig.DbConfig dbConfig = globalConfig.getDbConfig();
IndexName table = clazz.getAnnotation(IndexName.class);
String tableName = clazz.getSimpleName().toLowerCase(Locale.ROOT);
String tablePrefix = dbConfig.getTablePrefix();
String tablePrefix = dbConfig.getIndexPrefix();
boolean tablePrefixEffect = true;
String indexName;

View File

@ -14,7 +14,7 @@ import java.util.List;
**/
@Data
@Accessors(chain = true)
@IndexName(value = "easyes_document", shardsNum = 3, replicasNum = 2, keepGlobalPrefix = true, childClass = Comment.class,routing = "666")
@IndexName(value = "easyes_document", shardsNum = 3, replicasNum = 2, keepGlobalPrefix = true, childClass = Comment.class,routing = "testRouting")
public class Document {
/**
* es中的唯一id,字段名随便起,我这里演示用esId,你也可以用id(推荐),bizId等.

View File

@ -13,6 +13,7 @@ import cn.easyes.test.TestEasyEsApplication;
import cn.easyes.test.entity.Document;
import cn.easyes.test.mapper.DocumentMapper;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.geo.GeoDistance;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.common.unit.DistanceUnit;
@ -29,6 +30,7 @@ import org.elasticsearch.search.aggregations.metrics.ParsedMin;
import org.elasticsearch.search.aggregations.metrics.ParsedSum;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.*;
@ -161,6 +163,26 @@ public class AllTest {
}
// 3.查询
@Test
@Order(6)
public void testSQL() {
// 注意 sql中的from后面跟的是要被查询的索引名,也可以是索引别名(效果一样) 由于索引名可能会变,所以此处我采用别名ee_default_alias进行查询
String sql = "select count(*) from ee_default_alias where star_num > 0";
String jsonResult = documentMapper.executeSQL(sql);
System.out.println(jsonResult);
Assertions.assertNotNull(jsonResult);
}
@Test
@Order(6)
public void testDSL() {
String dsl = "{\"size\":10000,\"query\":{\"bool\":{\"must\":[{\"term\":{\"title.keyword\":{\"value\":\"测试文档2\",\"boost\":1.0}}}],\"adjust_pure_negative\":true,\"boost\":1.0}}\"track_total_hits\":2147483647}";
String jsonResult = documentMapper.executeDSL(dsl);
System.out.println(jsonResult);
Assertions.assertNotNull(jsonResult);
}
@Test
@Order(6)
public void testSelectOne() {
@ -491,6 +513,26 @@ public class AllTest {
Assertions.assertEquals(2, documents.size());
}
@Test
@Order(6)
public void testConditionFilter() {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.eq(Document::getStarNum, 10)
.filter(i -> i.eq(Document::getTitle, "测试文档10"));
List<Document> documents = documentMapper.selectList(wrapper);
Assertions.assertEquals(1, documents.size());
}
@Test
@Order(6)
public void testConditionMustNot() {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.in(Document::getStarNum, 10,11,12,13)
.mustNot(i->i.eq(Document::getTitle,"测试文档10").eq(Document::getTitle,"测试文档11"));
List<Document> documents = documentMapper.selectList(wrapper);
Assertions.assertEquals(2, documents.size());
}
@Test
@Order(6)
@ -760,12 +802,12 @@ public class AllTest {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
GeoPoint geoPoint = new GeoPoint(41.0, 116.0);
wrapper.geoDistance(Document::getLocation, 168.8, DistanceUnit.KILOMETERS, geoPoint);
// GeoDistanceSortBuilder geoDistanceSortBuilder = SortBuilders.geoDistanceSort(FieldUtils.val(Document::getLocation), geoPoint)
// .unit(DistanceUnit.KILOMETERS)
// .geoDistance(GeoDistance.ARC)
// .order(SortOrder.DESC);
//
// wrapper.sort(geoDistanceSortBuilder);
GeoDistanceSortBuilder geoDistanceSortBuilder = SortBuilders.geoDistanceSort(FieldUtils.val(Document::getLocation), geoPoint)
.unit(DistanceUnit.KILOMETERS)
.geoDistance(GeoDistance.ARC)
.order(SortOrder.DESC);
wrapper.sort(geoDistanceSortBuilder);
List<Document> documents = documentMapper.selectList(wrapper);
Assertions.assertEquals(4, documents.size());
}
@ -832,7 +874,7 @@ public class AllTest {
@Test
@Order(9)
public void testDSL() {
public void testComplex() {
// SQL写法
// where business_type = 1 and (state = 9 or (state = 8 and bidding_sign = 1)) or business_type = 2 and state in (2,3)

View File

@ -14,6 +14,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
@ -126,4 +128,10 @@ public class IndexTest {
boolean isOk = documentMapper.createIndex(wrapper);
Assertions.assertTrue(isOk);
}
@Test
public void testActiveIndex(){
String indexName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
documentMapper.setCurrentActiveIndex(indexName);
}
}

View File

@ -51,7 +51,12 @@ public class UpdateTest {
document2.setCustomField("乌拉巴拉中魔仙");
documentMapper.update(document2, wrapper);
// 关于case2 还有另一种省略实体的简单写法,这里不演示,后面章节有介绍,语法与MP一致
// 关于case2 另一种省略实体的简单写法,语法与MP一致
LambdaEsUpdateWrapper<Document> wrapper3 = new LambdaEsUpdateWrapper<>();
wrapper3.eq(Document::getTitle, title1);
wrapper3.set(Document::getContent,"推*技术过软")
.set(Document::getCustomField,"乌拉巴拉中魔仙");
documentMapper.update(null,wrapper);
}
@Test