ElasticSerch 的连接查询有两种方式实现

  • nested
  • parent和child关联查询

nested

  • 存储结构 
    nested的方式和其他字段一样,在同一个type里面存储,以数组的方式存储在 
    type里,格式如下:
PUT index_test/type_info/1000
{
"userId": 1000,
"mobile": "13301020202",
"nick": "梅西",
"vipType": 1,
"vipPoints": 1200,
"regTime": "2018-06-18 12:00:31",
"order": [
{
"status": 1,
"payMethod": 2,
"amount": 100,
"productCount": 3
},
{
"status": 2,
"payMethod": 2,
"amount": 230,
"productCount": 1
}
]
}
 

order 则为 nested

API查询方式 
直接用.连接对象的属性,如要要查找订单中状态=2的用户,直接使用order.status

GET index_test/type_info/_search
{
"query": {
"term": {
"order.status": 2
}
}
}

parent / child 关联的方式

  • 存储结构 
    parent / child 的存储结果跟nested不一样,是存储在不同的type里,通过parent来关联父子type关系,创建有父子关系的两个类型的时候必须在一个请求中创建


PUT index_test
{
"mappings": {
"type_info": {
"properties": {
"userId": {
"type": "integer"
},
"mobile": {
"type": "keyword"
},
"nick": {
"type": "keyword"
},
"vipType": {
"type": "integer"
},
"vipPoints": {
"type": "integer"
},
"regTime": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
}
}
},
"type_order": {
"_parent": {
"type": "type_info"
},
"properties": {
"amount": {
"type": "scaled_float",
"scaling_factor": 100
},
"payMethod": {
"type": "integer"
},
"status": {
"type": "integer"
},
"productCount": {
"type": "integer"
}
}
}
}
}
 

通过 _parent 来指定父type

  • 造点数据 
    添加几条用户数据,和普通的type一样,没有任何区别

PUT index_test/type_info/1000
{
"userId": 1000,
"mobile": "13301020202",
"nick": "梅西",
"vipType": 1,
"vipPoints": 1200,
"regTime": "2018-06-18 12:00:31"
}
PUT index_test/type_info/1001
{
"userId": 1001,
"mobile": "151232223",
"nick": "C罗",
"vipType": 1,
"vipPoints": 300,
"regTime": "2018-05-18 12:00:00"
}
 
PUT index_test/type_info/1002
{
"userId": 1002,
"mobile": "181829282",
"nick": "内马尔",
"vipType": 2,
"vipPoints": 1300,
"regTime": "2018-09-09 12:00:00"
}
 

添加几条订单数据,通过parent来指定type_info, 以下parent=xxx, xxx指的是父类型文档的_id编号。

PUT index_test/type_order/100?parent=1000
{
"userId": 1000,
"amount": 300,
"payMethod": 2,
"status": 3,
"productCount": 2
}
PUT index_test/type_order/101?parent=1000
{
"userId": 1000,
"amount": 250,
"payMethod": 1,
"status": 2,
"productCount": 1
}
PUT index_test/type_order/102?parent=1001
{
"userId": 1001,
"amount": 56,
"payMethod": 1,
"status": 2,
"productCount": 1
}
PUT index_test/type_order/103?parent=1002
{
"userId": 1002,
"amount": 78,
"payMethod": 2,
"status": 1,
"productCount": 2
}
PUT index_test/type_order/104?parent=1002
{
"userId": 1002,
"amount": 50,
"payMethod": 2,
"status": 1,
"productCount": 2
} 如果用java代码在新增doc的时候设置父类型的方法如下:
import com.alibaba.fastjson.JSON;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.transport.client.PreBuiltTransportClient; import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map; public class ElasticSearchMain { public static void main(String[] args) throws Exception {
TransportClient client = new PreBuiltTransportClient(Settings.EMPTY)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300)); Map<String, Object> objectMap = new HashMap<>();
objectMap.put("userId", 1001);
objectMap.put("amount", 30);
objectMap.put("payMethod", 2);
objectMap.put("status", 1);
objectMap.put("productCount", 2);
Map<String, Object> objectMap1 = addMapObjectDocToIndex(client, "index_test", "type_order", "105", objectMap);
System.out.println(JSON.toJSONString(objectMap1));
client.close();
} public static Map<String, Object> addMapObjectDocToIndex(TransportClient client, String index, String type, String docId, Map<String, Object> params) {
Map<String, Object> result = new HashMap<String, Object>();
boolean flag = false;
XContentBuilder source = null;
try {
source = createMapJson(params);
// 存json入索引中
IndexResponse response = null;
if (docId == null) {
// 使用默认的id
response = client.prepareIndex(index, type).setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE).setSource(source).get();
} else {
response = client.prepareIndex(index, type, docId).setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE).setSource(source).setParent("1001").get();
}
// 插入结果获取
RestStatus status = response.status();
if (status.getStatus() == 200 || status.getStatus() == 201) {
flag = true;
}
} catch (Exception e) {
e.printStackTrace();
}
result.put("success", flag);
result.put("msg", flag ? "新增成功" : "新增失败");
return result;
} /**
* 将Map转换成builder
*
* @param mapParam
* @return
* @throws Exception
*/
private static XContentBuilder createMapJson(Map<String, ?> params) throws Exception {
XContentBuilder source = XContentFactory.jsonBuilder().startObject();
for (Map.Entry<String, ?> entry : params.entrySet()) {
if (entry.getValue() != null && entry.getValue().toString().length() > 0) {
source.field(entry.getKey(), entry.getValue());
}
}
source.endObject();
return source;
}
}
 
  • API查询方式

  • 通过子type查询父type,返回父type信息 
    查询下单金额大于60的用户,通过 has_child 查询,返回用户信息
GET index_test/type_info/_search
{
"query": {
"has_child": {
"type": "type_order",
"query": {
"range": {
"amount": {
"gte": 60
}
}
}
}
}
}
 这个查询出来的结果是梅西和内马尔两个客户:
 
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1,
"hits": [
{
"_index": "index_test",
"_type": "type_info",
"_id": "1000",
"_score": 1,
"_source": {
"userId": 1000,
"mobile": "13301020202",
"nick": "梅西",
"vipType": 1,
"vipPoints": 1200,
"regTime": "2018-06-18 12:00:31"
}
},
{
"_index": "index_test",
"_type": "type_info",
"_id": "1002",
"_score": 1,
"_source": {
"userId": 1002,
"mobile": "181829282",
"nick": "内马尔",
"vipType": 2,
"vipPoints": 1300,
"regTime": "2018-09-09 12:00:00"
}
}
]
}
}

但是以上内马尔其实是有一个订单数量大于60和一个订单数量小于60,但是内马尔也被查出来了,测试结果说明,应该是只要有这样的子类型匹配到了,这个父类型的doc就会出来。

 
java api查询:查询payMethod为2的用户
 
 

import com.alibaba.fastjson.JSON;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.transport.client.PreBuiltTransportClient; import java.net.InetAddress; public class ElasticSearchMain { public static void main(String[] args) throws Exception {
TransportClient client = new PreBuiltTransportClient(Settings.EMPTY)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300));
//继续添加其他地址 BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); boolQuery.must(QueryBuilders.rangeQuery("amount").gte(60));
QueryBuilder hasChildQueryBuilder = QueryBuilders.hasChildQuery("type_order", boolQuery, ScoreMode.Avg); SearchResponse response = client.prepareSearch("index_test").setTypes("type_info").setQuery(hasChildQueryBuilder)
.setSize(10000).execute().actionGet(); for (SearchHit hit : response.getHits().getHits()) {
System.out.println(JSON.toJSONString(hit.getSource()));
}
//on shutdown
client.close();
} }
 
 
 
 
  • 通过父type查子type,返回子type信息 
    查询vip等级为1的用户下的订单,通过 has_parent 查询,返回订单信息
GET index_test/type_order/_search
{
"query": {
"has_parent": {
"parent_type": "type_info",
"query": {
"term": {
"vipType": {
"value": 1
}
}
}
}
}
}
 

nested 和 parent-child的区别以及使用场景

  • 主要区别: 
    由于存储结构的不同,nested和parent-child的方式有不同的应用场景 
    nested 所有实体存储在同一个文档,parent-child模式,子type和父type存储在不同的文档里。 
    所以查询效率上nested要高于parent-child,但是更新的时候nested模式下,es会删除整个文档再创建,而parent-child只会删除你更新的文档在重新创建,不影响其他文档。所以更新效率上parent-child要高于nested。

  • 使用场景: 
    nested:在少量子文档,并且不会经常改变的情况下使用。 
    比如:订单里面的产品,一个订单不可能会有成千上万个不同的产品,一般不会很多,并且一旦下单后,下单的产品是不可更新的。 
    parent-child:在大量文档,并且会经常发生改变的情况下使用。 
    比如:用户的浏览记录,浏览记录会很大,并且会频繁更新

elasticsearch 连接查询 基于es5.1.1的更多相关文章

  1. Elasticsearch 连接查询

    在一般的关系型数据库中,都支持连接操作. 在ES这种分布式方案中进行连接操作,代价是十分昂贵的. 不过ES也提供了相类似的操作,支持水平任意扩展,实现连接的效果. 其他内容,参考Elasticsear ...

  2. 基于百度地图SDK和Elasticsearch GEO查询的地理围栏分析系统(1)

    本文描述了一个系统,功能是评价和抽象地理围栏(Geo-fencing),以及监控和分析核心地理围栏中业务的表现. 技术栈:Spring-JQuery-百度地图WEB SDK 存储:Hive-Elast ...

  3. 【摸鱼神器】基于SSM风格的Java源代码生成器 单表生成 一对一、一对多、多对多连接查询生成

    一.序言 UCode Cms 是一款Maven版的Java源代码生成器,是快速构建项目的利器.代码生成器模块属于可拆卸模块,即按需引入.代码生成器生成SSM(Spring.SpringBoot.Myb ...

  4. oracle(sql)基础篇系列(二)——多表连接查询、子查询、视图

        多表连接查询 内连接(inner join) 目的:将多张表中能通过链接谓词或者链接运算符连接起来的数据查询出来. 等值连接(join...on(...=...)) --选出雇员的名字和雇员所 ...

  5. oracle中的连接查询与合并查询总结

    连接查询: 连接查询是指基于多张表或视图的查询.使用连接查询时,应指定有效的查询条件,不然可能会导致生成笛卡尔积.如现有部门表dept,员工表emp,以下查询因查询条件无效,而产生笛卡尔积:   (各 ...

  6. HQL连接查询

    HQL提供了连接查询机制如内连接,外连接,,还允许显示指定迫切内连接,和迫切外联结. 连接类型 内连接 inner join 或join 迫切内链接 inner join fetch 左外联结  le ...

  7. 学习如何看懂SQL Server执行计划(三)——连接查询篇

    三.连接查询部分 --------------------嵌套循环-------------------- /* UserInfo表数据少.Coupon表数据多嵌套循环可以理解为就是两层For循环,外 ...

  8. ORACLE复杂查询之连接查询

    一.传统的连接查询 1.交叉连接:返回笛卡尔积 WHERE中限定查询条件,可以预先过滤掉掉不符合条件的记录,返回的只是两个表中剩余记录(符合条件的记录)的笛卡尔积. 2.内连接:参与连接的表地位平等, ...

  9. MySQL之多表查询一 介绍 二 多表连接查询 三 符合条件连接查询 四 子查询 五 综合练习

    MySQL之多表查询 阅读目录 一 介绍 二 多表连接查询 三 符合条件连接查询 四 子查询 五 综合练习 一 介绍 本节主题 多表连接查询 复合条件连接查询 子查询 首先说一下,我们写项目一般都会建 ...

随机推荐

  1. Active Ball

    Active Ball is a simple game. All you need to do is aim at the food and shoot it, then collect the m ...

  2. ESA2GJK1DH1K基础篇: 测试APP使用SmartConfig绑定Wi-Fi 设备并控制设备

    前言 实现功能概要 STM32控制WI-Fi模块以AT指令TCP透传方式连接MQTT服务器, 实现MQTT通信控制. 测试准备工作(详细下载步骤请参考 硬件使用说明 ) 一,下载单片机程序 二,安装A ...

  3. Splay的基本操作(插入/删除,查询)

    Splay的基本操作(插入/删除,查询) 概述 这是一棵二叉查找树 让频繁访问的节点尽量靠近根 将查询,插入等操作的点"旋转"至根 树的高度均摊为$log_n$ 变量 int ro ...

  4. python paramiko模块简介及安装

    一:简介 paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接. 由于使用的是python这样的能够跨平台运行的语言,所以所有python支 ...

  5. CF1120D Power Tree(构造题,差分,最小生成树)

    很有趣的一道题. 首先可以对每个叶子进行编号.按照DFS到的顺序即可.(假设从 $1$ 到 $k$) 然后对每个点求出它管辖的所有叶子的编号.因为是DFS序所以这一定是个区间.设点 $u$ 的这个区间 ...

  6. Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理

    本文非常详尽地介绍了Java中的三个集合类 ArrayList,Vector与Stack <Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整 ...

  7. win10系统:VMware无法在Windows运行该怎么办?

     出现的问题: 解决方法: 点击“检查更新”或去官网下载最新版本 Vmware15.5.0(经过测试发现,Windows 10上面可以运行Vmware15.5.0 ) VMware Workstati ...

  8. SharePoint - Another Way to Delete Site Collection

    I had created a site collection. But there is a problem of web-frontend server (I did not know when ...

  9. Qt 实现超时锁屏

    最近使用Qt实现超时锁屏的功能(工控机触摸屏),当手长时间不触摸屏幕的时候,程序超时会显示锁屏窗口. 一.效果 主窗口超时显示锁屏窗口: 系统窗口超时显示锁屏窗口: 二.实现思路 首先开启一个线程用于 ...

  10. 分布式系统中我们会对一些数据量大的业务进行分拆,分布式系统中唯一主键ID的生成问题

    分布式全局唯一ID生成策略​ https://www.cnblogs.com/vandusty/p/11462585.html 一.背景 分布式系统中我们会对一些数据量大的业务进行分拆,如:用户表,订 ...