Nested
# Preface
In MySQL and other relational databases, the correlation between tables can be achieved using JOIN, but there is no JOIN in ES, so if you want to deal with this relationship, you need to understand nested parent-child types and large wide tables.
The bottom layer of ES is Lucene. Since Lucene actually does not support nested types, all documents are stored in Lucene in a flat structure. ES's support for nested documents is actually implemented in an opportunistic way. .
Nested documents are stored as independent documents, and then associated relationships are added. This will lead to a nested document actually storing N pieces of data at the bottom layer, and the update will involve nine-type updates, resulting in low efficiency. (If your business scenario involves more writing than reading, it is recommended that you use the parent-child type. If there is more reading than writing, use this nested type).
For nested types, we do not recommend that you use them unless you have to, because after introducing nested types, your subsequent CRUD will become very complicated. If there is a need for nesting + aggregation, the coding complexity will make you doubt your life. .
ES itself is more suitable for the "large wide table" mode. Don't use ES with the traditional relational database thinking. We can complete it by merging the fields and contents of multiple tables into one table (an index). Expected functions, avoiding the use of nested types as much as possible, are not only more efficient, but also more powerful.
Of course, it is reasonable to exist, and there are indeed certain scenarios where nested types are inevitably used. As the world's leading ES-ORM framework, we also provide support for this. Users can do without it, but we can't live without it!
# Nested types create indexes
-Automatic transmission mode:
According to the following configuration, the project will be started directly after the configuration is completed, and the framework will automatically create/update the index.
public class Document{
//Omit other fields ...
/**
* Nested type
*/
@IndexField(fieldType = FieldType.NESTED, nestedClass = User.class)
private List<User> users;
}
2
3
4
5
6
7
8
attention
Be sure to specify the type of fieldType=NESTED and its nestedClass as in the above example, otherwise the framework will not work properly.
-Manual shift mode
Method 1: according to the automatic transmission mode, configure the annotation, and then directly call the one-click generation API to generate the index.
documentMapper.createIndex();
Method 2: handmade, all fields are arranged by yourself, which is not recommended, and it is very troublesome.
LambdaEsIndexWrapper<Document> wrapper = new LambdaEsIndexWrapper<>();
//Omit other codes
wrapper.mapping(Document::getUsers, FieldType.NESTED);
2
3
attention
In manual shift mode, in addition to specifying the nestedClass through the annotation @TableField, you also need to specify the nested field through the wrapper, and then complete the index creation/update.
# Nested type CRUD
nested(String path, Consumer<Param> consumer);
nested(String path, Consumer<Param> consumer, ScoreMode scoreMode);
nested(boolean condition, String path, Consumer<Param> consumer);
nested(boolean condition, String path, Consumer<Param> consumer, ScoreMode scoreMode);
2
3
4
提示
Where path is the field name of the current query object. For example, I nested the User array in the Document object, and the field name is Users, and also nested the Faq array in the User object. When I need to query the user, I can satisfy it. When some data with specified conditions are passed in, the path is the string "users". When I need to query the data in Faq that meet some specified conditions, the path passed in is the string "users.faq". In addition, if you want to obtain the field in Lambda mode, you can use the tool class FieldUtils.val(R column) to obtain it.
There is no difference between adding, deleting and modifying non-nested types, so I won't go into details here.
Query example:
@Test
public void testNestedMatch() {
//Nested query queries data with age equal to 18 or 8 and password equal to 123.
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.nested("users", w ->
w.in(FieldUtils.val(User::getAge), 18, 8)
.eq(FieldUtils.val(User::getPassword), "123"));
List<Document> documents = documentMapper.selectList(wrapper);
System.out.println(documents);
//Nested query queries all data whose age meets 18 or whose question name matches' Is the size also 18'.
LambdaEsQueryWrapper<Document> wrapper2 = new LambdaEsQueryWrapper<>();
wrapper2.nested("users", w -> w.in("age", 18))
.or()
. nested ("users.faqs", w-> w.match ("FAQ _ name", "Is the size 18"));
List<Document> documents2 = documentMapper.selectList(wrapper2);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
For related demo, please refer to the test module of the source code ->test directory ->nested package.