背景
一个配方由多种原材料组成,需求是根据各种原材料的用量搜索出对应的配方
配方实体类
class Formula {private long id;private String name;private List<Material> materials;}class Material {@JsonProperty("material_id")private long materialId;private float amount;}
1、定义索引映射 Mapping
PUT /formula
{"mappings": {"properties": {"id": {"type": "long"},"name": {"type": "text"},"materials": {"type": "nested","properties": {"material_id": {"type": "long"},"amount": {"type": "float"}}}}}
}
2、添加测试数据
POST /formula/_doc/1
{"id": "1","name": "formula A","materials": [{ "material_id": "material_1", "amount": 100 },{ "material_id": "material_2", "amount": 50 }]
}POST /formula/_doc/2
{"id": "2","name": "formula B","materials": [{ "material_id": "material_2", "amount": 30 },{ "material_id": "material_3", "amount": 20 }]
}
3、查询
GET /formula/_search
{"query": {"bool": {"must": [{"match": {"name": "formula A"}},{"nested": {"path": "materials","query": {"bool": {"must": [{ "match": { "materials.material_id": "2" } },{ "range": { "materials.amount": { "gte": 40, "lte": 60 } } }]}}}}]}}
}
RestHighLevelClient
// nested
BoolQueryBuilder nestedBoolQueryBuilder = new BoolQueryBuilder();
nestedBoolQueryBuilder.must().add(QueryBuilders.matchPhraseQuery("materials.material_id", 1));
nestedBoolQueryBuilder.must().add(QueryBuilders.rangeQuery("materials.amount").from(40).to(60));
NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery("materials", nestedBoolQueryBuilder, ScoreMode.Avg);// query
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
boolQueryBuilder.must(nestedQueryBuilder);
// simple
boolQueryBuilder.must(QueryBuilders.matchQuery("name", "formula A"));SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(boolQueryBuilder);SearchRequest searchRequest = new SearchRequest(new String[]{index}, searchSourceBuilder);// response
SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
ElasticsearchClient
SearchResponse<Formula> response = elasticsearchClient.search(s -> s.index("formula").query(q -> q.match(t -> t.field("name").query("formula A"))).query(q -> q.nested(nq -> nq.path("materials").query(nq1 -> nq1.match(t -> t.field("materials.material_id").query("2"))).query(nq2 -> nq2.range(r -> r.field("materials.amount").from("40").to("60"))))),Formula.class
);