elasticsearch支持大table格式数据的搜索
一、问题源起
数据情况
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格式数据的搜索的更多相关文章
- 导入数据任务(id:373985)异常, 错误信息:解析导入文件错误,请检查导入文件内容,仅支持导入json格式数据及excel文件
		小程序导入,别人导出的数据库json文件,错误信息如下: 导入数据库失败, Error: Poll error, 导入数据任务(id:373985)异常,错误信息:解析导入文件错误,请检查导入文件内容 ... 
- 使用ElasticSearch服务从MySQL同步数据实现搜索即时提示与全文搜索功能
		最近用了几天时间为公司项目集成了全文搜索引擎,项目初步目标是用于搜索框的即时提示.数据需要从MySQL中同步过来,因为数据不小,因此需要考虑初次同步后进行持续的增量同步.这里用到的开源服务就是Elas ... 
- PetaPoco轻量级ORM框架 - 对Database类的进行扩展,可以返回Table格式数据
		一.有时我们需要将常用的功能添加到PetaPoco中的Database类中 实现方式有2种,以下以查询字段为例 1.通过扩展方式实现,此方式不改变被调用(Database)类名(只能增加方法) pub ... 
- SpringBoot RestController 同时支持返回xml和json格式数据
		@RestController 默认支持返回json格式数据,即使不做任何配置也能返回json数据 当接口需要支持xml或json两种格式数据时应该怎么做呢? 只要引入 Jackson xml的 ma ... 
- 分享一个jquery写的类似于百度的搜索框,(可动态配置,可单列或者table格式,可填充数据)
		需求:类似于百度的搜索框,可配置,可单列可table格式,可填充数据.页面可多次使用,简单,易用. 想法:使用jquery,css,ajax,前台调用,后台返回json数据. jquery代码: va ... 
- C# winfrom 写的一个搜索助手,可以按照标题和内容搜索,支持doc,xls,ppt,pdf,txt等格式的文件搜索
		C# winfrom 写的一个搜索助手,可以按照标题和内容搜索,指定目录后,遍历搜索文件和子目,现在只写了支持.DOC.DOCX.XLS.XLSX.PPT.PPTX.PDF.HTML.HTM.TXT等 ... 
- 【ElasticSearch】ES 读数据,写数据与搜索数据的过程
		ES读数据的过程: 1.ES客户端选择一个node发送请求,该请求作为协调节点(coordinating node): 2.corrdinating node 对 doc id 对哈希,找出该文档对应 ... 
- 使用Elasticsearch 与 NEST 库 构建 .NET 企业级搜索
		使用Elasticsearch 与 NEST 库 构建 .NET 企业级搜索 2015-03-26 dotNET跨平台 最近几年出现的云计算为组织和用户带来了福音.组织对客户的了解达到前所未有的透彻, ... 
- elasticsearch最全详细使用教程:搜索详解
		一.搜索API 1. 搜索API 端点地址从索引tweet里面搜索字段user为kimchy的记录 GET /twitter/_search?q=user:kimchy从索引tweet,user里面搜 ... 
随机推荐
- 如何获取SQL Server数据库连接字符串的某些部分
			有的时候需要获取SQL Server数据库连接字符串的某些部分.用正则表达式可能有点麻烦. 其实有一个比较简单的方法--使用SqlConnectionStringBuilder. var builde ... 
- 用Python预测双色球福利彩票中奖号码(请不要当真)
			前言 双色球是中国福利彩票的一种玩法. 红球一共6组,每组从1-33中抽取一个,六个互相不重复.然后蓝球是从1-16中抽取一个数字,这整个组成的双色球 python从零基础入门到实战 今天,我们就用P ... 
- C++手写内存池
			引言 使用new expression为类的多个实例分配动态内存时,cookie导致内存利用率可能不高,此时我们通过实现类的内存池来降低overhead.从不成熟到巧妙优化的内存池,得益于union的 ... 
- Linux必知必会的命令全集(持续更新)
			Linux有超过五百多种命令,每个命令还有十几二十种选项,令人抓狂,本文旨在整理本人工作常用的Linux命令,希望对大家有所帮助! 1.cd 跳转文件夹 最常用的命令,没有之一. cd # 进入 ... 
- DataGrid列显示隐藏配置
			1.列右键事件 private void data1_MouseRightButtonDown(object sender, MouseButtonEventArgs e) { ContextMenu ... 
- Build Web Server with Apache and Passenger
			Follow the instructions at 2.6. Generic installation, upgrade and downgrade method: via tarball of P ... 
- erlang学习笔记
			安装 Ubuntu Server上: sudo apt-get install erlang 如果安装时下载 太慢,可手工下载deb包( esl-erlang_16.a-rc1_ubuntu_prec ... 
- Java之JSP
			JSP JSP简介 JSP指的是 JavaServerPages ,Java服务器端页面,也和Servlet一样,用来开发动态web JSP页面中可以嵌入java代码为用户提供动态数据 JSP原理 J ... 
- MySQL Mac 终端环境变量配置
			MySQL Mac 终端环境变量配置 这里安装的是mysql-8.0.26-macos11-x86_64,M1Mac,原本打算安装arm64版本,但一直安装不了,就装了x86版本 安装完成MySQL之 ... 
- 题解 queen(留坑)
			传送门 博客园突然打不开了,奇奇怪怪的-- 少写个等号没看出来 nm写反了没看出来 考完5min全拍出来了 手残属性加持 不对拍等于爆零 yysy,我连卢卡斯定理的存在都忘了-- 发现要让一大堆皇后能 ... 
