Elasticsearch 父子关系维护和检索案例分享 elasticsearchbbosshas_childhas_parent
程序员文章站
2022-03-31 15:25:22
...
Elasticsearch 父子关系维护和检索案例分享,展示has_child和has_parent的基本用法。
本文涉及技术点:
1.准备工作
参考文档《高性能elasticsearch ORM开发库使用介绍》导入和配置es客户端
2.定义dsl文档
建立dsl配置文件-esmapper/indexparentchild.xml
3.实现has_child和has_parent检索
首先创建带公司和雇员关系的索引结构
然后通过bulk导入测试需要的公司和雇员数据,本案例通过加载配置文件中的dsl json data导入公司和雇员数据:
如果需要根据List集合批量导入测试数据,则参考以下方法:
List<Company>和List<Employee>列表分别对应需要批量导入的公司数据和雇员数据。需要特别说明的是Company和Employee这两个对象采用了注解@ESId来标注文档_id属性,采用@ESParentId属性来标注雇员和公司的关联属性:
接下来实现has_child和has_parent检索功能
通过junit测试用例执行上述功能
4.参考文档
https://blog.csdn.net/napoay/article/details/52032931
https://gitee.com/bboss/elasticsearchdemo/blob/master/src/test/java/org/frameworkset/elasticsearch/parentchild/ParentChildTest.java
https://gitee.com/bboss/elasticsearchdemo/blob/master/src/test/resources/esmapper/indexparentchild.xml
测试用例对应的工程
https://gitee.com/bboss/elasticsearchdemo
5 开发交流
elasticsearch技术交流群:166471282
elasticsearch微信公众号:bbossgroups
本文涉及技术点:
- 1.删除和创建公司/雇员父子关系的索引表
- 2.bulk批量导入json格式数据
- 3.ormapping方式bulk批量导入数据
- 4.采用@ESId指定文档_id
- 5.采用@ESParentId制定子文档的parent信息
- 6.基本的has_child和has_parent公司/雇员父子关系检索
1.准备工作
参考文档《高性能elasticsearch ORM开发库使用介绍》导入和配置es客户端
2.定义dsl文档
建立dsl配置文件-esmapper/indexparentchild.xml
<properties> <!-- 本案例适用于es 2.x,5.x 创建包含员工类型和公司类型的公司索引表 --> <property name="createCompanyEmployeeIndice"> <![CDATA[{ "settings": { "number_of_shards": 6, "index.refresh_interval": "5s" }, "mappings": { "company": { ##公司 "properties": { "name": { "type": "text", "fields": { ##dsl注释 定义精确查找的内部keyword字段 "keyword": { "type": "keyword" } } }, "city": { "type": "text", "fields": { ##dsl注释 定义精确查找的内部keyword字段 "keyword": { "type": "keyword" } } }, "country": { "type": "text", "fields": { ##dsl注释 定义精确查找的内部keyword字段 "keyword": { "type": "keyword" } } }, "companyId": { "type": "keyword" } } }, "employee": { ##雇员 "_parent": {##定义雇员和公司父子关联关系 "type": "company" }, "_routing": { "required": false }, "properties": { "name": { "type": "text", "fields": { ##dsl注释 定义精确查找的内部keyword字段 "keyword": { "type": "keyword" } } }, "birthday": { "type": "date", "format":"yyyy-MM-dd||epoch_millis" }, "hobby": { "type": "text", "fields": { ##dsl注释 定义精确查找的内部keyword字段 "keyword": { "type": "keyword" } } }, "companyId": { "type": "keyword" }, "employId": { "type": "keyword" } } } } }]]> </property> <!-- 导入公司信息: --> <property name="bulkImportCompanyData"> <![CDATA[ { "index": { "_id": "london" }} { "name": "London Westminster", "city": "London", "country": "UK" ,"companyId":"london"} { "index": { "_id": "liverpool" }} { "name": "Liverpool Central", "city": "Liverpool", "country": "UK" ,"companyId":"liverpool"} { "index": { "_id": "paris" }} { "name": "Champs Élysées", "city": "Paris", "country": "France","companyId":"paris" } ]]> </property> <!-- 导入雇员信息: --> <property name="bulkImportEmployeeData"> <![CDATA[ { "index": { "_id": 1, "parent": "london" }} { "name": "Alice Smith", "birthday": "1970-10-24", "hobby": "hiking" ,"companyId":"london","employeeId":1 } { "index": { "_id": 2, "parent": "london" }} { "name": "Mark Thomas", "birthday": "1982-05-16", "hobby": "diving" ,"companyId":"london","employeeId":2} { "index": { "_id": 3, "parent": "liverpool" }} { "name": "Barry Smith", "birthday": "1979-04-01", "hobby": "hiking" ,"companyId":"liverpool","employeeId":3} { "index": { "_id": 4, "parent": "paris" }} { "name": "Adrien Grand", "birthday": "1987-05-11", "hobby": "horses" ,"companyId":"paris","employeeId":4} { "index": { "_id": 5, "parent": "paris" }} { "name": "Adrien Green", "birthday": "1977-05-12", "hobby": "dancing" ,"companyId":"paris","employeeId":5} ]]> </property> <!--出生日期为条件检索公司信息--> <property name="hasChildSearchByBirthday"> <![CDATA[ { "query": { "has_child": { "type": "employee", "query": { "range": { "birthday": { "gte": #[birthday] } } } } } } ]]> </property> <!--姓名为条件检索公司信息--> <property name="hasChildSearchByName"> <![CDATA[ { "query": { "has_child": { "type": "employee", "score_mode": "max", "query": { "match": { "name": #[name] } } } } } ]]> </property> <!--最小员工数为条件检索公司信息--> <property name="hasChildSearchByMinChild"> <![CDATA[ { "query": { "has_child": { "type": "employee", "min_children": #[min_children], "query": { "match_all": {} } } } } ]]> </property> <!--检索员工信息--> <property name="hasParentSearchByCountry"> <![CDATA[ { "query": { "has_parent": { "type": "company", "query": { "match": { "country": #[country] } } } } } ]]> </property> </properties>
3.实现has_child和has_parent检索
首先创建带公司和雇员关系的索引结构
public void createIndice(){ ClientInterface clientUtil = ElasticSearchHelper.getConfigRestClientUtil("esmapper/indexparentchild.xml"); try { //删除mapping clientUtil.dropIndice("company"); } catch (ElasticSearchException e) { // TODO Auto-generated catch block e.printStackTrace(); } //创建mapping clientUtil.createIndiceMapping("company","createCompanyEmployeeIndice"); }
然后通过bulk导入测试需要的公司和雇员数据,本案例通过加载配置文件中的dsl json data导入公司和雇员数据:
public void importData(){ ClientInterface clientUtil = ElasticSearchHelper.getConfigRestClientUtil("esmapper/indexparentchild.xml"); //导入公司数据,并且实时刷新,测试需要,实际环境不要带refresh clientUtil.executeHttp("company/company/_bulk?refresh","bulkImportCompanyData",ClientUtil.HTTP_POST); //导入雇员数据,并且实时刷新,测试需要,实际环境不要带refresh clientUtil.executeHttp("company/employee/_bulk?refresh","bulkImportEmployeeData",ClientUtil.HTTP_POST); }
如果需要根据List集合批量导入测试数据,则参考以下方法:
/** * 通过List集合导入雇员和公司数据 */ public void importDataFromBeans() { ClientInterface clientUtil = ElasticSearchHelper.getRestClientUtil(); //导入公司数据,并且实时刷新,测试需要,实际环境不要带refresh List<Company> companies = buildCompanies(); clientUtil.addDocuments("company","company",companies,"refresh"); //导入雇员数据,并且实时刷新,测试需要,实际环境不要带refresh List<Employee> employees = buildEmployees(); clientUtil.addDocuments("company","employee",employees,"refresh"); }
List<Company>和List<Employee>列表分别对应需要批量导入的公司数据和雇员数据。需要特别说明的是Company和Employee这两个对象采用了注解@ESId来标注文档_id属性,采用@ESParentId属性来标注雇员和公司的关联属性:
public class Company extends ESBaseData { private String name; /** * 将companyId作为索引_id的值 */ @ESId private String companyId; 。。。。。。
public class Employee extends ESBaseData { /** * 通过ESId注解将employeeId指定为雇员的文档_id */ @ESId private int employeeId; /** * 通过ESParentId注解将companyId指定为雇员的parent属性,对应Company中的文档_id的值 */ @ESParentId private String companyId;
接下来实现has_child和has_parent检索功能
/** * 通过雇员生日检索公司信息 */ public void hasChildSearchByBirthday(){ ClientInterface clientUtil = ElasticSearchHelper.getConfigRestClientUtil("esmapper/indexparentchild.xml"); Map<String,Object> params = new HashMap<String,Object>(); params.put("birthday","1980-01-01"); ESDatas<Company> escompanys = clientUtil.searchList("company/company/_search","hasChildSearchByBirthday",params,Company.class); List<Company> companyList = escompanys.getDatas();//获取符合条件的公司 long totalSize = escompanys.getTotalSize(); } /** * 通过雇员姓名检索公司信息 */ public void hasChildSearchByName(){ ClientInterface clientUtil = ElasticSearchHelper.getConfigRestClientUtil("esmapper/indexparentchild.xml"); Map<String,Object> params = new HashMap<String,Object>(); params.put("name","Alice Smith"); ESDatas<Company> escompanys = clientUtil.searchList("company/company/_search","hasChildSearchByName",params,Company.class); List<Company> companyList = escompanys.getDatas();//获取符合条件的公司 long totalSize = escompanys.getTotalSize(); } /** * 通过雇员数量检索公司信息 */ public void hasChildSearchByMinChild(){ ClientInterface clientUtil = ElasticSearchHelper.getConfigRestClientUtil("esmapper/indexparentchild.xml"); Map<String,Object> params = new HashMap<String,Object>(); params.put("min_children",2); ESDatas<Company> escompanys = clientUtil.searchList("company/company/_search","hasChildSearchByMinChild",params,Company.class); List<Company> companyList = escompanys.getDatas();//获取符合条件的公司 long totalSize = escompanys.getTotalSize(); } /** * 通过公司所在国家检索雇员信息 */ public void hasParentSearchByCountry(){ ClientInterface clientUtil = ElasticSearchHelper.getConfigRestClientUtil("esmapper/indexparentchild.xml"); Map<String,Object> params = new HashMap<String,Object>(); params.put("country","UK"); ESDatas<Employee> escompanys = clientUtil.searchList("company/employee/_search","hasParentSearchByCountry",params,Employee.class); List<Employee> companyList = escompanys.getDatas();//获取符合条件的公司 long totalSize = escompanys.getTotalSize(); }
通过junit测试用例执行上述功能
@Test public void test(){ createIndice(); importData(); hasChildSearchByBirthday(); this.hasChildSearchByName(); this.hasChildSearchByMinChild(); this.hasParentSearchByCountry(); }
4.参考文档
https://blog.csdn.net/napoay/article/details/52032931
https://gitee.com/bboss/elasticsearchdemo/blob/master/src/test/java/org/frameworkset/elasticsearch/parentchild/ParentChildTest.java
https://gitee.com/bboss/elasticsearchdemo/blob/master/src/test/resources/esmapper/indexparentchild.xml
测试用例对应的工程
https://gitee.com/bboss/elasticsearchdemo
5 开发交流
elasticsearch技术交流群:166471282
elasticsearch微信公众号:bbossgroups