【ES】ES中的join方案一(Nested类型,基于6.3版本的java实现)

菜鸡一只,国庆真是玩了好几天,等到快上班的时候才开始又学习,找状态

本文来讲讲ES中的Join方案!

在数据库中,join是非常常见的操作!

其实就是将两张表的数据合并到一起,然后查询出结果数据,当然最后可能还需要一些过滤,这是数据库中的概念

 

在ES中也有join的方案,ES提供了两种api:

1、使用Nested结构存储(查询)数据

2、通过设置字段的type为join,然后使用hasChild和hasParent查询数据

官网相关链接:

https://www.elastic.co/guide/en/elasticsearch/reference/6.3/parent-join.html
https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl-nested-query.html
https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl-has-child-query.html
https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl-has-parent-query.html
https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl-parent-id-query.html
https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.3/java-joining-queries.html

 

举个很现实的例子:

表A:blog_new(博客)

表B:comments(评论)

他们之间的关系是一个问题会有多个答案,将这部分数据录入到ES中提供搜索

   blog_new
       |
       |
   comments

 

方案一:

通过Nested解决问题(把问题和答案当做一个document文档插入ES中):

##设置mapping
PUT blog_new
{
  "mappings": {
    "blog": {
      "properties": {
        "title": {
          "type": "text"
        },
        "body": {
          "type": "text"
        },
        "tags": {
          "type": "keyword"
        },
        "comments": {
          "type": "nested",
          "properties": {
            "name": {
              "type": "text"
            },
            "comment": {
              "type": "text"
            },
            "age": {
              "type": "short"
            },
            "stars": {
              "type": "short"
            },
            "date": {
              "type": "date"
            }
          }
        }
      }
    }
  }
}

##放进两条测试数据
PUT blog_new/blog/1
{
  "title": "Nest eggs",
  "body":  "Making your money work...",
  "tags":  [ "cash", "shares" ],
  "comments": [
    {
      "name":    "John Smith",
      "comment": "Great article",
      "age":     28,
      "stars":   4,
      "date":    "2014-09-01"
    },
    {
      "name":    "Alice White",
      "comment": "More like this please",
      "age":     31,
      "stars":   5,
      "date":    "2014-10-22"
    }
  ]
}

POST blog_new/blog/2
{
  "title": "Hero",
  "body": "Hero test body...",
  "tags": ["Heros", "happy"],
  "comments": [
    {
      "name": "steve",
      "age": 24,
      "stars": 5,
      "comment": "Nice article..",
      "date": "2014-10-22"
    }
  ]
}

 

当我们对于这样的数据结构进行增删改查的时候,需要通过nested关键字来处理

1、查询数据:

##查询查询评论的人的名称匹配john和他/她的年龄是28岁
GET blog_new/blog/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "comments",
            "query": {
              "bool": {
                "must": [
                  {
                    "match": {
                      "comments.name": "john"
                    }
                  },
                  {
                    "match": {
                      "comments.age": 28
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

 2、新增数据:

##可以把整条数据全部读出来,然后整条update,
POST blog_new/blog/2
{
  "title": "Hero",
  "body": "Hero test body...",
  "tags": ["Heros", "happy"],
  "comments": [
    {
      "name": "steve",
      "age": 24,
      "stars": 5,
      "comment": "Nice article..",
      "date": "2014-10-22"
    }
  ]
}
##也可以通过script来更新部分(某个字段),还是比较麻烦的
POST blog_new/blog/2/_update
{
    "script" : {
        "source": "ctx._source.tags.add(params.tag)",
        "lang": "painless",
        "params" : {
            "tag" : "blue"
        }
    }
}

POST blog_new/blog/2/_update
{
	"script": {
		"source": "ctx._source.comments.add(params.commentuser)",
		"lang": "painless",
		"params": {
			"commentuser": {
				"name": "steve",
				"age": 70,
				"stars": 5,
				"comment": "very very good article...",
				"date": "2014-10-22"
			}
		}
	}
}

3、删除数据:

##删除文档id=1的所有名字叫做John Smith的comments(评论)
POST  blog_new/blog/1/_update
{
 "script": {
    "lang": "painless",
    "source": "ctx._source.comments.removeIf(it -> it.name == 'John Smith');"
 }
}

4、修改数据:

##修改文档id=2,名字叫做steve的comments(评论),年龄修改为75,评论内容修改为very very good article...

POST blog_new/blog/2/_update
{
  "script": {
    "source": "for(e in ctx._source.comments){if (e.name == 'steve') {e.age = 75; e.comment= 'very very good article...';}}" 
  }
}

5、与之对应的JavaAPI:

    public static void main(String[] args) throws Exception {
        ElasticConfigration es = new ElasticConfigration();
        //自己写的es的TransportClient创建
        es.initialize();
        //获得client对象
        TransportClient client = es.client();
        testNestedQuery(client);
    }



    public static void testNestedQuery(TransportClient client) {
        NestedQueryBuilder nestedQueryBuilder =
                new NestedQueryBuilder("comments", QueryBuilders.boolQuery()
                        .must(QueryBuilders.matchQuery("comments.name", "john"))
                        .must(QueryBuilders.matchQuery("comments.age",28)),ScoreMode.None);

        SearchResponse searchResponse = client.prepareSearch("blog_new")
                .setTypes("blog")
                .addSort("_score", SortOrder.DESC)
                .setQuery(nestedQueryBuilder)
                .setFrom(0).setSize(50).execute().actionGet();

        printSearchResponse(searchResponse);

    }

 public static void testNestedUpdateQuery(TransportClient client) throws IOException {

//        UpdateResponse updateResponse = client.prepareUpdate("blog_new","blog","2").setScript(
//                new Script("for(e in ctx._source.comments){if (e.name == 'steve') {e.age = 25; e.comment= 'very very good article...';}}")).execute().actionGet();
//        System.out.println(updateResponse.status());
        
        /**
         *  如果要插入一个新的comment,需要在params的Map中,插入JSONObject对象
         *  直接使用json格式的字符串,会报错:tried to parse field [null] as object, but found a concrete value
         */
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("name","ll");
        jsonObject.put("age",75);
        jsonObject.put("stars",5);
        jsonObject.put("comment","very very good article...");
        jsonObject.put("date","2014-10-22");
        jsonObject.put("name","ll");

        HashMap hashMap = new HashMap<String,Object>();
        hashMap.put("commentuser",jsonObject);
        UpdateResponse updateResponse = client
                         .prepareUpdate("blog_new","blog","2")
                         .setScript(new Script(ScriptType.INLINE,"painless",
                            "ctx._source.comments.add(params.commentuser)", hashMap))
                .execute().actionGet();
        System.out.println(updateResponse.status());

    }



    public static void printSearchResponse( SearchResponse searchResponse) {
        // 命中的记录数
        long totalHits = searchResponse.getHits().getTotalHits();
        System.out.println("totalHits:" + totalHits);
        for (SearchHit searchHit : searchResponse.getHits()) {
            // 打分
            float score = searchHit.getScore();
            System.out.println("score:" + score);
            // 文章id
            int id = Integer.parseInt(searchHit.getId());
            System.out.println("doc_id:" + id);
            String sourceAsString = searchHit.getSourceAsString();
            System.out.println(sourceAsString);
        }
    }

 

本文参考了一些其他人的博客和官网,官网列在最前面了,建议大家都去看下,有助于整合思路,有一篇文章我觉得写的超好的,大家也可以看看,如下:

《干货 | Elasticsearch Nested类型深入详解》:https://blog.csdn.net/laoyang360/article/details/82950393(作者:铭毅天下)

好,方案二,我在下一篇文章里面再写吧,不然文章太长,看的我自己都头疼,更别说各位看官了~

老话,菜鸡一只,如果有任何问题,欢迎留言!

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值