一、问题源起

数据情况

TableMeta, 保存table的元数据,通过fileId关联具体的GridFS文件;

id name creator fileId
1 table1 mango f1
2 table2 mango f2

table内包含列名和具体的行数据;

不同类型的table,列的名字和数量都可能不同;

from fport to toport location
192.168.1.1 11 192.168.1.12 11 chaoyang
192.168.1.2 22 192.168.1.13 22 tongzhou

搜索要求

支持所有类型的table的搜索;

支持全字段的搜索;

只返回表内命中的行,并进行高亮;

二、开发环境

elasticsearch 6.8.12

java 12.0.2 2019-07-16

Java(TM) SE Runtime Environment (build 12.0.2+10)

Java HotSpot(TM) 64-Bit Server VM (build 12.0.2+10, mixed mode, sharing)

三、elastic search对array的支持情况

扁平化数组元素

默认情况下elastic search会将数组内部对象的字段进行扁平化处理,这样就会丢失掉元素的独立性。

直接index一个文档

PUT my_array_index/_doc/1
{
"group" : "fans",
"user" : [
{
"first" : "John",
"last" : "Smith"
},
{
"first" : "Alice",
"last" : "White"
}
]
} {
"_index":"my_array_index",
"_type":"_doc",
"_id":"1",
"_version":1,
"result":"created",
"_shards":{
"total":2,
"successful":1,
"failed":0
},
"_seq_no":0,
"_primary_term":1
}

elastic search 内部会将文档转化为如下形式再进行索引

{
"group" : "fans",
"user.first" : [ "alice", "john" ],
"user.last" : [ "smith", "white" ]
}

扁平化处理将所有数组元素对象的相同字段值合并到一起作为一个数组,这样就丢失了user.first和user.last之间的对应关系,类似下边的查询即使没有Alice Smith这个人也可以命中

GET my_index/_search
{
"query": {
"bool": {
"must": [
{ "match": { "user.first": "Alice" }},
{ "match": { "user.last": "Smith" }}
]
}
}
} {
"took":2,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"skipped":0,
"failed":0
},
"hits":{
"total":1,
"max_score":0.5753642,
"hits":[
{
"_index":"my_array_index",
"_type":"_doc",
"_id":"1",
"_score":0.5753642,
"_source":{
"group":"fans",
"user":[
{
"first":"John",
"last":"Smith"
},
{
"first":"Alice",
"last":"White"
}
]
}
}
]
}
}

使用nested数据类型文档化数组元素

elastic search内部提供了nested数据类型,可以将数组元素作为单独的隐藏的内部文档进行索引,从而保持文档之间的独立性;

将字段映射为nested类型

PUT my_nested_index
{
"mappings": {
"_doc": {
"properties": {
"user": {
"type": "nested"
}
}
}
}
} {
"acknowledged":true,
"shards_acknowledged":true,
"index":"my_nested_index"
}

index文档

PUT my_nested_index/_doc/1
{
"group" : "fans",
"user" : [
{
"first" : "John",
"last" : "Smith"
},
{
"first" : "Alice",
"last" : "White"
}
]
} {
"_index":"my_nested_index",
"_type":"_doc",
"_id":"1",
"_version":1,
"result":"created",
"_shards":{
"total":2,
"successful":1,
"failed":0
},
"_seq_no":0,
"_primary_term":1
}

elastic search提供了单独的nested query 来支持nested类型

GET my_nested_index/_search
{
"query": {
"nested": {
"path": "user",
"query": {
"bool": {
"must": [
{ "match": { "user.first": "Alice" }},
{ "match": { "user.last": "Smith" }}
]
}
}
}
}
} {
"took":3,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"skipped":0,
"failed":0
},
"hits":{
"total":0,
"max_score":null,
"hits":[ ]
}
}

nested query提供了inner_hits类支持字段高亮,从高亮信息中可以看到,offset字段指出了命中了数组中的第几个元素;

GET my_nested_index/_search
{
"query": {
"nested": {
"path": "user",
"query": {
"bool": {
"should": [
{ "match": { "user.first": "Alice" }},
{ "match": { "user.last": "smith" }}
]
}
},
"inner_hits": {
"highlight": {
"fields": {
"*": {}
}
}
}
}
}
} {
"took":8,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"skipped":0,
"failed":0
},
"hits":{
"total":1,
"max_score":0.6931472,
"hits":[
{
"_index":"my_nested_index",
"_type":"_doc",
"_id":"1",
"_score":0.6931472,
"_source":{
"group":"fans",
"user":[
{
"first":"John",
"last":"Smith"
},
{
"first":"Alice",
"last":"White"
}
]
},
"inner_hits":{
"user":{
"hits":{
"total":2,
"max_score":0.6931472,
"hits":[
{
"_index":"my_nested_index",
"_type":"_doc",
"_id":"1",
"_nested":{
"field":"user",
"offset":0
},
"_score":0.6931472,
"_source":{
"first":"John",
"last":"Smith"
},
"highlight":{
"user.last":[
"<em>Smith</em>"
]
}
},
{
"_index":"my_nested_index",
"_type":"_doc",
"_id":"1",
"_nested":{
"field":"user",
"offset":1
},
"_score":0.6931472,
"_source":{
"first":"Alice",
"last":"White"
},
"highlight":{
"user.first":[
"<em>Alice</em>"
]
}
}
]
}
}
}
}
]
}
}

总结

经过以上的研究可以看到,elastic search提供的nested数据类型基本满足我们的目标要求,接下来使用具体的table数据做进一步的研究;

四、使用nested数据类型索引Table数据

elastic search索引数据结构

字段名字 字段类型 描述
id string 主键
name string table的名字
creator string 创建者
content (object) array 行数据数组

elastic search mapping

PUT tables
{
"mappings": {
"_doc": {
"properties": {
"id": {
"type": "keyword"
},
"name": {
"type": "keyword"
},
"creator": {
"type": "keyword"
},
"content": {
"type": "nested"
}
}
}
}
} {
"acknowledged": true,
"shards_acknowledged": true,
"index": "tables"
}

index 一个Table data

PUT tables/_doc/1
{
"id":"1",
"name":"table1",
"creator":"mango",
"content":[
{
"0":"192.168.1.1",
"1":"11",
"2":"192.168.1.12",
"3":"11",
"4":"chaoyang"
},
{
"0":"192.168.1.2",
"1":"22",
"2":"192.168.1.13",
"3":"22",
"4":"tongzhou"
},
{
"0":"192.168.3",
"1":"33",
"2":"192.168.1.14",
"3":"33",
"4":"daxing"
}
]
} {
"_index":"tables",
"_type":"_doc",
"_id":"1",
"_version":1,
"result":"created",
"_shards":{
"total":2,
"successful":1,
"failed":0
},
"_seq_no":0,
"_primary_term":1
}

search Table data

搜索所有列

限制只返回Table的元数据信息

限制只返回命中行的信息

返回命中行的高亮信息

post /tables/_search/
{
"from":0,
"size":20,
"_source":{
"excludes":[
"content"
]
},
"query":{
"nested":{
"path":"content",
"query":{
"query_string":{
"fields":[
"content.*"
],
"query":"tongzhou 192.168.1.1"
}
},
"inner_hits":{
"from":0,
"size":2,
"highlight":{
"fields":{
"*":{ }
}
}
}
}
}
} {
"took":19,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"skipped":0,
"failed":0
},
"hits":{
"total":1,
"max_score":0.9808292,
"hits":[
{
"_index":"tables",
"_type":"_doc",
"_id":"1",
"_score":0.9808292,
"_source":{
"creator":"mango",
"name":"table1",
"id":"1"
},
"inner_hits":{
"content":{
"hits":{
"total":2,
"max_score":0.9808292,
"hits":[
{
"_index":"tables",
"_type":"_doc",
"_id":"1",
"_nested":{
"field":"content",
"offset":0
},
"_score":0.9808292,
"_source":{
"0":"192.168.1.1",
"1":"11",
"2":"192.168.1.12",
"3":"11",
"4":"chaoyang"
},
"highlight":{
"content.0":[
"<em>192.168.1.1</em>"
]
}
},
{
"_index":"tables",
"_type":"_doc",
"_id":"1",
"_nested":{
"field":"content",
"offset":1
},
"_score":0.9808292,
"_source":{
"0":"192.168.1.2",
"1":"22",
"2":"192.168.1.13",
"3":"22",
"4":"tongzhou"
},
"highlight":{
"content.4":[
"<em>tongzhou</em>"
]
}
}
]
}
}
}
}
]
}
}

elasticsearch支持大table格式数据的搜索的更多相关文章

  1. 导入数据任务(id:373985)异常, 错误信息:解析导入文件错误,请检查导入文件内容,仅支持导入json格式数据及excel文件

    小程序导入,别人导出的数据库json文件,错误信息如下: 导入数据库失败, Error: Poll error, 导入数据任务(id:373985)异常,错误信息:解析导入文件错误,请检查导入文件内容 ...

  2. 使用ElasticSearch服务从MySQL同步数据实现搜索即时提示与全文搜索功能

    最近用了几天时间为公司项目集成了全文搜索引擎,项目初步目标是用于搜索框的即时提示.数据需要从MySQL中同步过来,因为数据不小,因此需要考虑初次同步后进行持续的增量同步.这里用到的开源服务就是Elas ...

  3. PetaPoco轻量级ORM框架 - 对Database类的进行扩展,可以返回Table格式数据

    一.有时我们需要将常用的功能添加到PetaPoco中的Database类中 实现方式有2种,以下以查询字段为例 1.通过扩展方式实现,此方式不改变被调用(Database)类名(只能增加方法) pub ...

  4. SpringBoot RestController 同时支持返回xml和json格式数据

    @RestController 默认支持返回json格式数据,即使不做任何配置也能返回json数据 当接口需要支持xml或json两种格式数据时应该怎么做呢? 只要引入 Jackson xml的 ma ...

  5. 分享一个jquery写的类似于百度的搜索框,(可动态配置,可单列或者table格式,可填充数据)

    需求:类似于百度的搜索框,可配置,可单列可table格式,可填充数据.页面可多次使用,简单,易用. 想法:使用jquery,css,ajax,前台调用,后台返回json数据. jquery代码: va ...

  6. C# winfrom 写的一个搜索助手,可以按照标题和内容搜索,支持doc,xls,ppt,pdf,txt等格式的文件搜索

    C# winfrom 写的一个搜索助手,可以按照标题和内容搜索,指定目录后,遍历搜索文件和子目,现在只写了支持.DOC.DOCX.XLS.XLSX.PPT.PPTX.PDF.HTML.HTM.TXT等 ...

  7. 【ElasticSearch】ES 读数据,写数据与搜索数据的过程

    ES读数据的过程: 1.ES客户端选择一个node发送请求,该请求作为协调节点(coordinating node): 2.corrdinating node 对 doc id 对哈希,找出该文档对应 ...

  8. 使用Elasticsearch 与 NEST 库 构建 .NET 企业级搜索

    使用Elasticsearch 与 NEST 库 构建 .NET 企业级搜索 2015-03-26 dotNET跨平台 最近几年出现的云计算为组织和用户带来了福音.组织对客户的了解达到前所未有的透彻, ...

  9. elasticsearch最全详细使用教程:搜索详解

    一.搜索API 1. 搜索API 端点地址从索引tweet里面搜索字段user为kimchy的记录 GET /twitter/_search?q=user:kimchy从索引tweet,user里面搜 ...

随机推荐

  1. APICloud的真机wifi连接问题

    APICloud的真机wifi连接问题 在APICloud的真机wifi连接时需要注意事项与解决问题. 1.首先将项目拉取到本地,用APICloud Studio 2打开(也可以用webStorm配置 ...

  2. windows10激活方法

    原文转自:http://www.ylmfwin100.com/ylmf/8643.html 现在市面上大致有两种主流激活方法,一种是通过激活码来激活,另外一种是通过激活工具来激活.但是激活工具有个弊端 ...

  3. ifix vba 读取计算机中的txt文件,截取字符串显示

    利用vba脚本,使用Scripting.FileSystemObject对象可以实现对文本文件的操作,下面以一个朋友的实际例子为例将截获的字符串进行页面显示. Private Sub CommandB ...

  4. js学习笔记之公告逐行显示

    $(function(){ var newsListHeight = $(".news-list").height(); //获得内容的高度 var newsConHeight = ...

  5. netty系列之:netty中的ByteBuf详解

    目录 简介 ByteBuf详解 创建一个Buff 随机访问Buff 序列读写 搜索 其他衍生buffer方法 和现有JDK类型的转换 总结 简介 netty中用于进行信息承载和交流的类叫做ByteBu ...

  6. 网安日记③之通过iis搭建ftp并使用通过serv-u搭建ftp

    通过iis搭建ftp并使用通过serv-u搭建ftp 安装iis的ftp访问 由于在安装iis时勾选了ftp服务,我们直接在iis界面右键ftp服务打开属性查看本地路径 在电脑目录下打开安装目录,并在 ...

  7. 面试官疯狂问我:char和varchar的区别 怎么办?愣着干嘛?进来白嫖啊!

    MySQL的修仙之路,图文谈谈如何学MySQL.如何进阶!(已发布) 面前突击!33道数据库高频面试题,你值得拥有!(已发布) 大家常说的基数是什么?(已发布) 讲讲什么是慢查!如何监控?如何排查?( ...

  8. myvimrc

    set nocompatible execute pathogen#infect() call pathogen#helptags() call pathogen#incubate() imap jk ...

  9. 区块链-NFT 的实现原理

    作者:林冠宏 / 指尖下的幽灵.转载者,请: 务必标明出处. 博客:http://www.cnblogs.com/linguanh/ 掘金:https://juejin.im/user/1785262 ...

  10. 零基础学Java之Java学习笔记(三):变量和数据类型

    为什么需要变量? 变量是一个程序的基本组成单位. 变量的概念: 变量相当于内存中一个数据存储空间的表示,你可以把变量看做是一个房间的门牌号,通过门牌号我们可以找到房 间,而通过变量名可以访问到变量(值 ...