Condition constructor
Tips
If you have already understood the conditional constructor of MP before, then we suggest that you directly pull to the end of the article and look at the three items of index, enableMust2Filter, and&or that are not in MP, and the others are consistent with MP. Wrapper supports two ways to create:
- Direct new, such as new
LambdaEsQueryWrapper<>()
. - Created by EsWrappers.lambdaQuery(), it can support the scene of chain programming, and match the Wrappers of MP
Description
- The first input parameter boolean condition that appears below indicates whether the condition is added to the last generated statement, for example: query.like(StringUtils.isNotBlank(name), Entity::getName, name) .eq(age!=null && age >= 0, Entity::getAge, age)
- Multiple methods in the following code blocks are to complete the input parameters of individual boolean types from top to bottom, the default is true
- The generic Param appearing below are all subclass instances of Wrapper (all have all methods of AbstractWrapper)
- R in the input parameters of the following methods is a generic type, in a normal wrapper it is a String, and in a LambdaWrapper it is a function (for example: Entity::getId, Entity is the entity class, getId is the getMethod of the field id)
- The R columns in the parameters of the following methods all represent database fields. When the specific type of R is String, it is the database field name (the field name is the database keyword itself wrapped with escape characters!)! Instead of the entity class data field name !!!, and when the specific type of R is SFunction, the project runtime does not support eclipse's own compiler!!!
- The following examples use ordinary wrappers, and the input parameters of Map and List are all expressed in json form!
- If the Map or List entered is empty during use, it will not be added to the last generated sql!
- If you have any questions, just click the open source code to read, if you don't understand the function click me to learn new knowledge (opens new window)
warning
Transporting Wrappers in RPC calls is not supported and deprecated
- The wrapper is heavy
- Transfer wrapper can be analogous to receiving values for your controller with map (developing for a while, maintaining crematorium)
- The correct RPC call posture is to write a DTO for transmission, and then the callee performs corresponding operations according to the DTO
- We refuse to accept any issues or even prs related to RPC transport Wrapper errors
# AbstractWrapper
Description
The parent class of QueryWrapper(LambdaEsQueryWrapper) and UpdateWrapper(LambdaEsUpdateWrapper) is used to generate the where condition of the statement, and the entity attribute is also used to generate the where condition of the statement. Note: The where condition generated by entity is not related to the where condition generated by each api** Behavior**
# QueryWrapper
Description
Inherited from AbstractWrapper , its own internal property entity is also used to generate where conditions and LambdaEsQueryWrapper
# UpdateWrapper
Description
Inherited from AbstractWrapper , its own internal property entity is also used to generate where conditions and LambdaEsUpdateWrapper
# allEq
allEq(Map<R, V> params)
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
2
3
4
individual parameter description
params : key is the database field name, value is the field value null2IsNull : If it is true, the isNull method is called when the value of the map is null, and when it is false, the value of null is ignored.
- Example 1: allEq({id:1,name:"Pharaoh",age:null})--->id = 1 and name = 'Pharaoh' and age is null
- Example 2: allEq({id:1,name:"Pharaoh",age:null}, false)--->id = 1 and name = 'Pharaoh'
allEq(BiPredicate<R, V> filter, Map<R, V> params)
allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
2
3
4
individual parameter description
filter : filter function, whether to allow the field to be passed into the comparison condition params and null2IsNull : same as above
- Example 1: allEq((k,v) -> k.indexOf("a") >= 0, {id:1,name:"Pharaoh",age:null})--->name = 'Old king' and age is null
- Example 2: allEq((k,v) -> k.indexOf("a") >= 0, {id:1,name:"Pharaoh",age:null}, false)--->name = 'Pharaoh'
# eq
eq(R column, Object val)
eq(boolean condition, R column, Object val)
2
- is equal to =
- Example: eq("name", "Pharaoh")--->name = 'Pharaoh'
# ne
ne(R column, Object val)
ne(boolean condition, R column, Object val)
2
- not equal to !=
- Example: ne("name", "Pharaoh")--->name != 'Pharaoh'
# gt
gt(R column, Object val)
gt(boolean condition, R column, Object val)
2
- greater than >
- Example: gt("age", 18)--->age > 18
# ge
ge(R column, Object val)
ge(boolean condition, R column, Object val)
2
- greater than or equal to >=
- Example: ge("age", 18)--->age >= 18
# lt
lt(R column, Object val)
lt(boolean condition, R column, Object val)
2
- less than <
- Example: lt("age", 18)--->age < 18
# le
le(R column, Object val)
le(boolean condition, R column, Object val)
2
- less than or equal to <=
- Example: le("age", 18)--->age <= 18
# between
between(R column, Object val1, Object val2)
between(boolean condition, R column, Object val1, Object val2)
2
- BETWEEN value 1 AND value 2
- Example: between("age", 18, 30)--->age between 18 and 30
# notBetween
notBetween(R column, Object val1, Object val2)
notBetween(boolean condition, R column, Object val1, Object val2)
2
- NOT BETWEEN value 1 AND value 2
- Example: notBetween("age", 18, 30)--->age not between 18 and 30
# like
like(R column, Object val)
like(boolean condition, R column, Object val)
2
- LIKE '%value%'
- Example: like("name", "King")--->name like '%王%'
# notLike
notLike(R column, Object val)
notLike(boolean condition, R column, Object val)
2
- NOT LIKE '%value%'
- Example: notLike("name", "King")--->name not like '%王%'
# likeLeft
likeLeft(R column, Object val)
likeLeft(boolean condition, R column, Object val)
2
- LIKE '%value'
- Example: likeLeft("name", "King")--->name like '%King'
# likeRight
likeRight(R column, Object val)
likeRight(boolean condition, R column, Object val)
2
- LIKE 'value %'
- Example: likeRight("name", "King")--->name like 'King%'
# isNull
isNull(R column)
isNull(boolean condition, R column)
2
- Field IS NULL
- Example: isNull(Document::getTitle)--->title is null
# isNotNull
isNotNull(R column)
isNotNull(boolean condition, R column)
2
- Field IS NOT NULL
- Example: isNotNull(Document::getTitle)--->title is not null
# in
in(R column, Collection<?> value)
in(boolean condition, R column, Collection<?> value)
2
- Field in (value.get(0), value.get(1), ...)
- Example: in("age",{1,2,3})--->age in (1,2,3)
in(R column, Object... values)
in(boolean condition, R column, Object... values)
2
-field in (v0, v1, ...)
- Example: in("age", 1, 2, 3)--->age in (1,2,3)
# notIn
notIn(R column, Collection<?> value)
notIn(boolean condition, R column, Collection<?> value)
2
- Field not in (value.get(0), value.get(1), ...)
- Example: notIn("age",{1,2,3})--->age not in (1,2,3)
notIn(R column, Object... values)
notIn(boolean condition, R column, Object... values)
2
- Field not in (v0, v1, ...)
- Example: notIn("age", 1, 2, 3)--->age not in (1,2,3)
# groupBy
groupBy(R... columns)
groupBy(boolean condition, R... columns)
2
- Grouping: GROUP BY field, ...
- Example: groupBy(Document::getId,Document::getTitle)--->group by id,title
# orderByDesc
orderByDesc(R...columns)
orderByDesc(boolean condition, R... columns)
2
- Sort: ORDER BY field, ... DESC
- Example: orderByDesc(Document::getId,Document::getTitle)--->order by id DESC,title DESC
# limit
limit(Integer n);
limit(Integer m, Integer n);
2
3
- limit n How many pieces of data are returned at most, which is equivalent to n in limit n in MySQL, and the usage is the same.
- limit m,n skips m pieces of data and returns n pieces of data at most, which is equivalent to limit m,n or offset m limit n in MySQL
- Example: limit(10)--->Only return up to 10 pieces of data
- Example: limit(2,5)--->Skip the first 2 pieces of data, start the query from the 3rd piece, and query 5 pieces of data in total
Tips
If the n parameter is not specified, its default value is 10000. If you do a single query and do not want too much data with low scores, you need to manually specify n to limit it. In addition, the function of this parameter is consistent with the size and from in Es. It is only introduced for compatibility with MySQL syntax. Users can choose one of the two according to their own habits. When both are used, only one will take effect, and the later specified will override the first specified. of.
# from
from(Integer from)
- Start the query from the first number of data, which is equivalent to m in limit (m, n) in MySQL.
- Example: from(10)--->Start query from the 10th data
# size
size(Integer size)
- How many pieces of data are returned at most, which is equivalent to n in limit (m,n) or n in limit n in MySQL
- Example: size(10)--->Only return up to 10 pieces of data
Tips
If you do a single query and don't want too much data with low scores, you need to manually specify the size to limit it.
# set
set(String column, Object val)
set(boolean condition, String column, Object val)
2
- SQL SET fields
- Example: set("name", "Old Litou")
- Example: set("name", "")--->Database field value becomes empty string
- Example: set("name", null)--->Database field value becomes null
# index
index(String indexName)
index(boolean condition, String indexName)
2
Tips
You can use wrapper.index(String indexName) to specify which index this query is to act on. If this query is to be queried from multiple indexes, the index names can be separated by commas, for example, wrapper.index("index1","index2"...). The index name specified in the wrapper has the highest priority. If it is not specified, the index name configured in the entity class is taken. If the entity class is not configured, the lowercase entity name is taken as the index name of the current query. For the case where there is no wrapper in the interface such as insert/delete/update, if you need to specify the index name, you can directly add the index name to the input parameter of the corresponding interface. You can refer to the following example:
Document document = new Document();
// Omit the code that assigns value to document
String indexName = "laohan";
insert(document, indexName);
2
3
4
# enableMust2Filter
enableMust2Filter(boolean enable)
enableMust2Filter(boolean condition, boolean enable)
2
Tips
Whether to convert the must query conditions into filter query conditions, you can directly specify whether the conditions of this query are converted in the wrapper. If not specified, it will be obtained from the global configuration file. If it is not configured in the configuration file, it will not be converted by default. The must query condition calculates the score, and the filter does not calculate the score. Therefore, in the query scenario where the score does not need to be calculated, enabling this configuration can improve the query performance a little.
# and&or (emphasis)
apologies
The parameters of ES are actually encapsulated in a tree-like data structure, so there is no way for AND and OR in ES to be consistent with MySQL. In order to achieve a syntax that is almost the same as MP, the author has lost his mind. .. Fortunately, in the end, the grammar of 99% similarity is basically achieved, and there is still 1% that needs to be learned by users.
The correspondence table between MySQL and ES syntax is as follows
MySQL | ES |
---|---|
and(condition1, condition2...) | must BoolQueryBuilder(condition1, condition2) |
or(condition1, condition2...) | should BoolQueryBuilder(condition1, condition2) |
condition 1.or(). condition 2 | should condition 1, should condition 2 |
AND introduction, AND in EE actually encapsulates multiple query conditions in AND brackets into a BoolQueryBuilder as a whole, and then the whole and other parameters are encapsulated in Must by default, and the function is similar to AND in MySQL (condition 1, condition 2 , condition 3...)
AND API
and(Consumer<Param> consumer)
and(boolean condition, Consumer<Param> consumer)
2
- AND
- Example: and(i -> i.eq(Document::getTitle, "Hello").ne(Document::getCreator, "Guy"))--->and (title ='Hello' and creator != ' Guy' )
OR introduction, OR in EE is the same as OR in MP, and supports 2 kinds, one is or(), which is used as a connector, and the other is or (condition 1, condition 2, condition 3).
- The first or(): used to reset the must conditions before and after the or() connector to the should query conditions
- The second or (condition 1, condition 2, condition 3...): It is used to encapsulate multiple query conditions in parentheses into a BoolQueryBuilder as a whole, and then the whole and other parameters are encapsulated in Should by default, with similar functions OR(Condition 1, Condition 2, Condition 3...) in MySQL
- The third special case is that the first or() connector appears in and(condition1.or().condition2...) or or(condition1.or().condition2...) , at this time, or() resets the must condition to the should condition, and the scope is limited to the parentheses, and the query conditions outside the parentheses are not affected.
or()
or(boolean condition)
2
- Splicing OR Notes: Actively calling or means that the next method is not connected with and! (If you do not call or, the default is to use and connection)
- Example: eq("Document::getId",1).or().eq(Document::getTitle,"Hello")--->id = 1 or title ='Hello'
or(Consumer<Param> consumer)
or(boolean condition, Consumer<Param> consumer)
2
OR
Example: or(i -> i.eq(Document::getTitle, "Hello").ne(Document::getCreator, "Guy"))--->or (title ='Hello' and status != ' Guy' )
Special case
Example: eq(Document::getTitle,"Hello") .and(i->i.eq(Document::getCreator,"Bob").or().eq(Document::getCreator,"Tom"))---> title="Hello" and(creator=" Bob" or creator="Tom")
In addition, some usage scenarios are as shown in the figure below. All query fields, query types, matching rules, etc. are not fixed and can be freely selected by the user. In this case, it will be very difficult to use the above syntax code. Write, you might as well use the queryStringQuery API to solve, use it to solve, the whole syntax is more like MySQL, and the flexibility and efficiency are very high.
Pre-knowledge learning
Before officially entering the topic, let's first understand the index of ES, because there are many novice who do not understand ES index, so here is a brief description of the keyword type and text type of ES, so as not to step on the pit below, you can skip this directly if you already know it. Section introduction.
The keyword type in ES is basically the same as the field in MySQL. When we need to perform exact matching, left fuzzy, right fuzzy, full fuzzy, sorting aggregation and other operations on the query field, the index type of the field needs to be keyword type. When we need to perform a word segmentation query on a field, we need the type of the field to be text type, and specify the tokenizer (use the ES default tokenizer if not specified, the effect is usually not ideal). When the same field, we need to treat it as When the keyword type is used, and it needs to be used as the text type, our index type is the keyword_text type. In EE, you can add the annotation @TableField(fieldType = FieldType.KEYWORD_TEXT) to the field, so that the field will be created as keyword The +text double type is shown in the figure below. It is worth noting that when we query the field as a keyword type, ES requires the incoming field name to be "field name.keyword". When the field is queried as a text type, Just use the original field name directly.
It should also be noted that if the index type of a field is created to query only the keyword type (as shown in the figure below), you do not need to append .keyword to its name, and you can query it directly.
After the long-winded, officially entered the topic, queryStringQuery API:
queryStringQuery(String queryString);
The queryString string is our query condition. We can use StringBuilder to splicing query fields and values into the final query statement. The above picture is taken as an example, I will demonstrate a scenario, please ignore the rationality of the scenario, because I chose it blindly: Suppose my query condition is: field: the creator is equal to Lao Wang, and the creator participle matches "next door" (for example: The old man next door, the old king next door), or the creator contains a big pig's hoof, the corresponding code is as follows:
@Test
public void testQueryString() {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
StringBuilder sb = new StringBuilder();
sb.append("(")
.append("(")
.append("creator.keyword")
.append(":")
.append("Pharaoh")
.append(")")
.append("AND")
.append("(")
.append("creator")
.append(":")
.append("Next door")
.append(")")
.append(")")
.append("OR")
.append("(")
.append("creator.keyword")
.append(":")
.append("*big pig's hoof*")
.append(")");
// The final splicing of sb is: ((creator.keyword: Pharaoh)AND(creator: next door))OR(creator.keyword:*big pig's hoof*), which can be said to be very similar to MySQL syntax
wrapper.queryStringQuery(sb.toString());
List<Document> documents = documentMapper.selectList(wrapper);
System.out.println(documents);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Every time a line of query parameters is passed on the front-end parameter page, we append the corresponding parameters to sb and we are done. class, its full path is: cn.easyes.core.toolkit.QueryUtils We refactor the above code using this utility class as follows:
@Test
public void testQueryStringQueryMulti() {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
String queryStr = QueryUtils.combine(Link.OR,
QueryUtils.buildQueryString(Document::getCreator, "Pharaoh", Query.EQ, Link.AND),
QueryUtils.buildQueryString(Document::getCreator, "Next door", Query.MATCH))
+ QueryUtils.buildQueryString(Document::getCreator, "*Big Pig's Hoof*", Query.EQ);
wrapper.queryStringQuery(queryStr);
List<Document> documents = documentMapper.selectList(wrapper);
System.out.println(documents);
}
2
3
4
5
6
7
8
9
10
11
Is it a lot more elegant? I have encapsulated the enumeration Query and Link for you, and you can use it directly. If you don't understand the meaning of the enumeration, you can click it directly to view it. I have detailed comments in the source code.