- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
通常数据库进行分库分表后,目前比较常规的作法,是通过将数据异构到Elasticsearch来提供分页列表查询服务;在创建Elasticsearch索引时,基本都是会参考目前的业务需求、关系数据库中的类型以及对数据的相关规划来定义相关字段mapping的类型. 在Elasticsearch的mapping中的列(或则叫属性),有几个比较重要的参数( 更多参数参考官方文档 ) 。
列类型: type 。
指定了该列的数据类型,常用的有 text , keyword , date , long , double , boolean 以及 object 和 nested ,不同的类型也有对应的不同查询方式,创建之后是不能修改的; 。
是否可索引: index 。
该 index 选项控制字段值是否被索引。它接受 true or false ,并且默认为 true . 未索引的字段不可查询,当然也不能做为排序字段.
但是在实际的开发过程中,又会有需求对现有的mapping的type进行修改(类似对MySQL数据表的字段进行DDL操作)的诉求。比如商品上的价格 price 字段,按原来的业务分析,只需要提供数据返回即可,在创建索引时类型定义了 keyword 了,并且 index 设置成了 false ,这时我们需要根据价格的范围查询或则进行排序操作,就希望对mapping进行调整,将类型修改成数字类型,索引也需要加上;今天针对Elasticsearch的Mapping类型进行修改,讨论几个可行的方案 。
遇到问题第一时间,我们应该是查询官方文档是否有相关的操作说明,在官方文档中,确实还能找到对已有mapping更新的相关api put-mapping ,通过这个文档,很快可以找到文档中对修改已有mapping的列的方式( 参考官方文档 ),同时也提到的通过 reindex 的方式来修改已有类型的方式; 。
除了支持的 mapping parameters 外,您不能更改现有字段的映射或字段类型。更改现有字段可能会使已编制索引的数据无效。如果您需要更改字段的映射,请使用正确的映射创建一个新索引并将您的数据重新索引 reindex 到该索引中.
如原来索引的mapping如下 。
PUT /users
{
"mappings" : {
"properties": {
"user_id": {
"type": "long"
}
}
}
}
//加一了两条数据
POST /users/_doc?refresh=wait_for
{
"user_id" : 12345
}
POST /users/_doc?refresh=wait_for
{
"user_id" : 12346
}
这时想修改 user_id 的类型为 keyword ,我们直接是修改不了的.
//尝试直接修改type,行不通,会报错
PUT /users/_mapping
{
"properties": {
"user_id": {
"type": "keyword"
}
}
}
//报错信息
{
"error": {
"root_cause": [
{
"type": "illegal_argument_exception",
"reason": "mapper [user_id] of different type, current_type [long], merged_type [keyword]"
}
],
"type": "illegal_argument_exception",
"reason": "mapper [user_id] of different type, current_type [long], merged_type [keyword]"
},
"status": 400
}
按官方文档说的 reindex 重新索引可按以下步骤操作 。
new_users
将 user_id
的类型定义成 keyword
PUT /new_users
{
"mappings" : {
"properties": {
"user_id": {
"type": "keyword"
}
}
}
}
user
索引标记为只读 控制我们的应用系统,数据停写不再向老索引中写数据,并且最好对老索引进行只读操作设置,保证在reindex的过程中,不要生产新数据,导致新老索数据不一致; 。
//设置索引为读写的
PUT /users/_settings
{
"settings": {
"index.blocks.write": true
}
}
user
索引中的数据迁移到 new_users
中
POST /_reindex
{
"source": {
"index": "users"
},
"dest": {
"index": "new_users"
}
}
reindex 还有很多的参数可以配置,包括从远程的一个集群迁移数据都是可以的,详细可参考: Reindex API 。
如果新的索引的mapping的定义与原索引的定义有差异的,会按新索引定义的 dynamic 规则进行数据的迁移,具体的,可以参考: dynamic 。
该 dynamic 设置控制是否可以动态添加新字段。它接受三种设置:
值 | 说明 |
---|---|
true | 新检测到的字段被添加到映射中。( 默认 ); 新增的数据类型的规则,可以参考: dynamic-mapping |
false | 忽略新检测到的字段。这些字段不会被编入索引,因此将无法搜索,但仍会出现在 _source 返回的命中字段中。这些字段不会添加到映射中,必须明确添加新字段。 |
strict | 如果检测到新字段,则会抛出异常并拒绝文档。必须将新字段显式添加到映射中。 |
同时将原 user 索引标记为可读写 。
//设置索引为可读写
PUT /users/_settings
{
"settings": {
"index.blocks.write": false
}
}
//为索引增加别名 基本格式
PUT /<index>/_alias/<alias>
POST /<index>/_alias/<alias>
//为new_users索引增加别名users
PUT /new_users/_alias/users
//没有删除老索引前,是增加不了别名的,需要先删除老别名
{
"error": {
"root_cause": [
{
"type": "invalid_alias_name_exception",
"reason": "Invalid alias name [users], an index exists with the same name as the alias",
"index_uuid": "8Rbq_32BTHC4CoO_CqWdXA",
"index": "users"
}
],
"type": "invalid_alias_name_exception",
"reason": "Invalid alias name [users], an index exists with the same name as the alias",
"index_uuid": "8Rbq_32BTHC4CoO_CqWdXA",
"index": "users"
},
"status": 400
}
该方案,不需要对原索引做操作,在线即可进行,并且操作步骤也简单;也是官方文档提供的方案.
当数据最大时,这个数据迁移会比较耗时 。
当数据量小时,并且希望mapping比较规整好看,该方案是比较推荐的。当数据量大时,可能该方案在数据迁移过程中会比较耗时,需要评估是否可行; 。
为不同的目的以不同的方式索引同一个字段通常很有用。这就是 multi-fields 的目的。例如,一个 string 字段可以映射为text用于全文搜索的字段,也可以映射 keyword 为用于排序或聚合的字段; 在这个方案中,应用的是mapping参数 fields 来对同一个列,定义多种数据类型;详细[【官方文档】multi-fields] ( https://www.elastic.co/guide/en/elasticsearch/reference/7.5/multi-fields.html ) 。
fields
属性 还是以上面的 users 这个索引为例,我们还是想将 user_id 的类型定义成 keyword ; 。
PUT /users/_mapping
{
"properties":{
"user_id":{
"type":"long",
"fields":{
"raw":{
"type":"keyword"
}
}
}
}
}
操作完成后,在 users 的 user_id 列下,就会多出一个 raw 的子属性;在我们正常写数据 user_id 时,会自动生成这两个索引,一个是 long 类型的 user_id ,以及 keyword 类型的 user_id.raw (注意这里有个点,跟子对象访问方式一样); 在put mapping时, type 参数必需给,并且需要跟原来的类型一致, fields 中新定义的子属性可以多个; 。
针对历史数据需要处理,可以借助 _update_by_query 来更新数据,只需要将原来的索引再写一次,即可将新加的字段写入数据.
POST /users/_update_by_query
{
"query":{
"exists":{
"field":"user_id"
}
},
"script":{
"source":"ctx._source.user_id=ctx._source.user_id ",
"lang":"painless"
}
}
// query 部分为需要更新数据过滤条件,可根据业务规则写
// script 更数据的逻辑,这个基本可以不改
通过这方式不会影响原来的索引数据,可以不用修改现在的应用程序的读写方式,对应用程序一切按原来逻辑执行,对应用方无感知,非常优化。只需要有使用新类型的场景使用即可,可以说影响是最小的; 同时只是做了一个定义,执行速度是非常快的,对Elasticsearch服务基本不会有太大影响;并且对于同一个列可以定义多个类型,比如商品名称,在多国多语言环境下可以根据不同语言定义多个列,对应使用不同的分词器; 。
老数据不会自动创建索引,因为需要多出新的索引来,会增加额外的存储; 。
1、需要对多一列创建多个索引类型时,是一个非常推荐的方案; 2、对于新索引,只有新业务使用,对老数据没有诉求的,也非常推荐该方案; 。
copy_to 是将多个字段的值,合并到一个字段中,便于搜索。但是也可以实现一个字段存在多个类型的需求。详细参考 【官方文档】copy_to 。
还是用上面的 users 这个索引为例,为 user_id 创建一个copy列: user_id_raw 类型定义成 keyword 。
PUT /users/_mapping
{
"properties":{
"user_id_raw":{
"type":"keyword",
"copy_to":"user_id"
}
}
}
这个方案与 方案2:multi-fields 基本是一样的,只是创建列的方式不同,优缺点都一样; 。
作者:京东零售 周德东 。
来源:京东云开发者社区 转载请注明来源 。
最后此篇关于ElasticsearchMapping类型修改的文章就讲到这里了,如果你想了解更多关于ElasticsearchMapping类型修改的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试编写一个相当多态的库。我遇到了一种更容易表现出来却很难说出来的情况。它看起来有点像这样: {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE
谁能解释一下这个表达式是如何工作的? type = type || 'any'; 这是否意味着如果类型未定义则使用“任意”? 最佳答案 如果 type 为“falsy”(即 false,或 undef
我有一个界面,在IAnimal.fs中, namespace Kingdom type IAnimal = abstract member Eat : Food -> unit 以及另一个成功
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: What is the difference between (type)value and type(va
在 C# 中,default(Nullable) 之间有区别吗? (或 default(long?) )和 default(long) ? Long只是一个例子,它可以是任何其他struct类型。 最
假设我有一个案例类: case class Foo(num: Int, str: String, bool: Boolean) 现在我还有一个简单的包装器: sealed trait Wrapper[
这个问题在这里已经有了答案: Create C# delegate type with ref parameter at runtime (1 个回答) 关闭 2 年前。 为了即时创建委托(dele
我正在尝试获取图像的 dct。一开始我遇到了错误 The function/feature is not implemented (Odd-size DCT's are not implemented
我正在尝试使用 AFNetworking 的 AFPropertyListRequestOperation,但是当我尝试下载它时,出现错误 预期的内容类型{( “应用程序/x-plist” )}, 得
我在下面收到错误。我知道这段代码的意思,但我不知道界面应该是什么样子: Element implicitly has an 'any' type because index expression is
我尝试将 SignalType 从 ReactiveCocoa 扩展为自定义 ErrorType,代码如下所示 enum MyError: ErrorType { // .. cases }
我无法在任何其他问题中找到答案。假设我有一个抽象父类(super class) Abstract0,它有两个子类 Concrete1 和 Concrete1。我希望能够在 Abstract0 中定义类
我想知道为什么这个索引没有用在 RANGE 类型中,而是用在 INDEX 中: 索引: CREATE INDEX myindex ON orders(order_date); 查询: EXPLAIN
我正在使用 RxJava,现在我尝试通过提供 lambda 来订阅可观察对象: observableProvider.stringForKey(CURRENT_DELETED_ID) .sub
我已经尝试了几乎所有解决问题的方法,其中包括。为 提供类型使用app.use(express.static('public'))还有更多,但我似乎无法为此找到解决方案。 index.js : imp
以下哪个 CSS 选择器更快? input[type="submit"] { /* styles */ } 或 [type="submit"] { /* styles */ } 只是好
我不知道这个设置有什么问题,我在 IDEA 中获得了所有注释(@Controller、@Repository、@Service),它在行号左侧显示 bean,然后转到该 bean。 这是错误: 14-
我听从了建议 registering java function as a callback in C function并且可以使用“简单”类型(例如整数和字符串)进行回调,例如: jstring j
有一些 java 类,加载到 Oracle 数据库(版本 11g)和 pl/sql 函数包装器: create or replace function getDataFromJava( in_uLis
我已经从 David Walsh 的 css 动画回调中获取代码并将其修改为 TypeScript。但是,我收到一个错误,我不知道为什么: interface IBrowserPrefix { [
我是一名优秀的程序员,十分优秀!