腾讯旗下CDN国际版(EdgeOne)限时活动,测速并分享至Twitter(x.com)和Facebook可获取2个免费套餐
活动链接
https://edgeone.ai/get-free-plan
截图


腾讯旗下CDN国际版(EdgeOne)限时活动,测速并分享至Twitter(x.com)和Facebook可获取2个免费套餐
https://edgeone.ai/get-free-plan


文章指出特斯拉利用激光雷达车队在奥斯汀等地收集数据,并非放弃纯视觉路线,而是为Robotaxi建立高精度的地面实况(Ground Truth)。通过时间戳同步技术,将激光雷达的精确测量值与摄像头图像自动配对,高效生成海量训练数据,从而“教导”纯视觉系统独立完成距离和速度估算,加速自动驾驶的实现。
《日经亚洲》报道,来自八个国家14个学术机构的研究人员被发现在论文中隐藏提示,以操纵AI审稿人给出正面评价,引发了关于学术诚信和AI在同行评审中作用的激烈辩论。
介绍如何判断两个IP地址是否属于同一个网段,解释其底层原理,并提供Go语言的实现代码。
下面的sql查询同一张表的数据,差异仅在where条件不同,但是同样是active =true的记录在返回的结果中,排序顺序不同,这是为什么
1 | SELECT id,name FROM `tag` WHERE corp_id =4 ORDER BY active DESC LIMIT 10; |
这两条SQL语句返回的数据顺序不一致的原因在于第一条SQL语句中 active 列可能存在除了 true (或 1) 以外的其他值,比如 false (或 0) 或者 NULL。
让我们更详细地分析一下:
SQL 1:
1 | SELECT id, name FROM `tag` WHERE corp_id = 4 ORDER BY active DESC LIMIT 10; |
corp_id = 4: 首先过滤出 corp_id 为 4 的所有行。active DESC: 然后按照 active 列降序排序。 这意味着:true (或 1) 的行会排在前面。false (或 0) 的行会排在 true 之后。NULL 的行会排在 false 之前,但具体位置取决于数据库实现。 MySQL会默认把 NULL 值放在最前面SQL 2:
1 | SELECT id, name FROM `tag` WHERE (corp_id = 4) AND active = true ORDER BY active DESC LIMIT 10; |
corp_id = 4 AND active = true: 首先过滤出 corp_id 为 4 并且 active 为 true 的所有行。active DESC: 然后按照 active 列降序排序。 由于 WHERE 子句已经确保了所有行的 active 都是 true,所以这个排序实际上是多余的,因为所有行的 active 值都相同。关键区别在于WHERE子句的过滤条件:
corp_id = 4 的行,然后根据 active 进行排序,NULL值可能在最前面。corp_id = 4 并且 active = true 的行。 排序没有实际作用。举例说明:
假设你的 tag 表有以下数据(简化):
| id | name | corp_id | active |
|---|---|---|---|
| 1 | A | 4 | true |
| 2 | B | 4 | false |
| 3 | C | 4 | NULL |
| 4 | D | 4 | true |
| 5 | E | 4 | false |
| 6 | F | 4 | NULL |
| 7 | G | 4 | true |
| 8 | H | 4 | false |
| 9 | I | 4 | NULL |
| 10 | J | 4 | true |
| 11 | K | 4 | false |
SQL 1 的结果 (可能):
假设 MySQL 把 NULL 放在最前面排序
id = 3, name = C (active = NULL)id = 6, name = F (active = NULL)id = 9, name = I (active = NULL)id = 1, name = A (active = true)id = 4, name = D (active = true)id = 7, name = G (active = true)id = 10, name = J (active = true)id = 2, name = B (active = false)id = 5, name = E (active = false)id = 8, name = H (active = false)SQL 2 的结果:
id = 1, name = A (active = true)id = 4, name = D (active = true)id = 7, name = G (active = true)id = 10, name = J (active = true)active = true 的行,直到达到10行。 因为排序没意义,结果具有不确定性,取决于数据库内部的行存储顺序。active 列只包含 true 和 false,并且没有 NULL 值,那么这两条SQL语句的结果在 id 和 name 上可能相同,但在结果排序上可能不同(第一条语句明确排序了,第二条排序实质上无效)。active 列包含 NULL 值,这是最可能导致结果不同的原因,因为第一条语句会受到NULL值排序的影响。如何解决:
如果你的意图是只获取 active 为 true 的记录,那么第二条SQL语句是正确的选择。
如果你想要获取所有 corp_id = 4 的记录,并让 active 为 true 的记录排在最前面,可以使用以下SQL语句(假设你想把 NULL 值放在最后):
1 | SELECT id, name |
或者,更简单的使用 IFNULL 函数(MySQL 特性):
1 | SELECT id, name |
这条语句将 NULL 视为 0 (false),从而将 true 的行放在最前面。 如果你想将 NULL 视为 True, 将 0 改为 1 即可.
或者,增加排序字段,用id和active同时排序:
1 | SELECT id,name |
选择哪种方法取决于你想要如何处理 active 列中的 NULL 值。 最重要的是理解你的数据和你想达到的结果,然后选择正确的SQL语句。
在 Elasticsearch 中,向已有索引的 mapping 里新增字段时,如果你尝试添加一个已经存在的字段(即字段名重复),会出现以下情况:
不能修改已存在字段的类型:Elasticsearch 不允许修改已存在字段的类型或映射配置。如果你试图用不同的类型或属性重新定义已存在字段,操作会失败并报错,因为字段映射一旦确定,不能更改[3][5]。
如果新增字段名和已有字段完全一致且映射相同,则相当于“重复添加”,这通常不会有实际影响,但也不会做任何修改,mapping 保持不变。
如果新增字段名重复但映射不同,Elasticsearch 会拒绝更新 mapping,返回错误提示,防止数据索引混乱[3][5]。
新增字段时,必须保证字段名唯一且映射合理,否则需要新建索引并通过 Reindex API 迁移数据来实现字段类型变更[3][5]。
总结:
| 操作场景 | 结果说明 |
|---|---|
| 新增字段名不存在 | 成功添加字段到 mapping |
| 新增字段名已存在且映射相同 | 无变化,mapping 不会重复添加 |
| 新增字段名已存在但映射不同 | 报错,更新失败,不能修改字段类型 |
因此,新增字段时如果字段名重复且映射不同,ES 会拒绝更新 mapping 并报错,你需要通过新建索引和重新索引数据来变更字段类型。
这是 Elasticsearch 设计的限制,保证倒排索引结构的稳定性和数据一致性[3][5]。
[1] https://codeshellme.github.io/2021/02/es-mappings/
[2] https://blog.csdn.net/weixin_48990070/article/details/120342866
[3] http://masikkk.com/article/Elasticsearch-Mapping/
[4] http://www.zbpblog.com/blog-458.html
[5] https://www.cnblogs.com/wupeixuan/p/12514843.html
[6] https://www.cnblogs.com/shoufeng/p/10648835.html
[7] https://blog.csdn.net/yxd179/article/details/82907796
[8] https://scsundefined.gitbooks.io/elasticsearch-reference-cn/content/s12/00_mapping.html
Elasticsearch 中 text 和 keyword 是两种常用的字符串字段类型,它们的主要区别在于是否进行分词,进而影响索引和查询行为。
text 与 keyword 的区别| 特性 | text |
keyword |
|---|---|---|
| 是否分词 | 会分词,进行全文分析 | 不分词,整体作为一个词项索引 |
| 适用场景 | 需要全文检索、模糊查询、相关度排序 | 需要精确匹配、过滤、排序、聚合 |
| 支持的查询类型 | match、match_phrase 等全文查询 |
term、terms 精确查询 |
| 支持聚合/排序 | 不支持(性能差且不合理) | 支持 |
| 存储限制 | 无字符长度限制 | 默认最大长度256字符,超过不索引(可配置) |
| 典型用途 | 文章内容、评论、描述等长文本 | 用户名、邮箱、标签、状态、ID等 |
通常为了兼顾全文检索和精确匹配,字段会定义成 text 类型,同时添加一个 keyword 子字段:
1 | PUT my_index |
这样,title 字段既可以全文检索,也可以做精确匹配和聚合。
1 | GET my_index/_search |
1 | GET my_index/_search |
1 | GET my_index/_search |
Elasticsearch 不支持直接修改已有字段的类型。如果想给已有索引新增 keyword 子字段,需要使用 动态模板或在创建索引时定义好,或者新建索引并重建数据。
示例:新增字段时定义 multi-fields
1 | PUT my_index/_mapping |
如果字段已存在且类型不同,修改会失败,需要新建索引。
text 适合全文检索,支持分词和相关度评分,不能用于聚合和排序。keyword 适合精确匹配、过滤、排序和聚合,不分词。text + keyword 多字段映射,兼顾两种需求。match 查询 text 字段,精确匹配用 term 查询 keyword 字段。以上内容基于 Elasticsearch 官方设计理念及社区实践总结[1][2][3][4][6]。如果需要,我可以帮你写具体的 mapping 和查询模板。
[1] https://www.cnblogs.com/hahaha111122222/p/12177377.html
[2] https://blog.csdn.net/UbuntuTouch/article/details/128904528
[3] https://cloud.tencent.com/developer/article/2357713
[4] https://bbs.huaweicloud.com/blogs/410730
[5] https://www.cnblogs.com/Rawls/p/10069670.html
[6] https://blog.csdn.net/weixin_41860630/article/details/126471632
[7] https://blog.51cto.com/u_15730090/5510216
[8] https://blog.51cto.com/u_15278282/2933670
Elasticsearch 中字段类型繁多,合理选择字段类型对索引效率、查询性能和存储空间都有重要影响。以下是常用字段类型的全面介绍及区别解析,结合核心、复合、地理和特殊类型,帮助你理解它们的作用和应用场景。
| 类型 | 说明 | 适用场景与特点 |
|---|---|---|
| text | 用于全文检索的字符串字段,会经过分词器拆分成词项并建立倒排索引。 | 适合长文本、描述、文章内容等需要模糊匹配、分词查询的场景。不支持排序和精确聚合。 |
| keyword | 不分词的字符串字段,整体作为一个词项索引。 | 适合存储结构化短文本,如用户名、邮箱、标签、状态码等。支持精确匹配、过滤、排序和聚合。 |
| long | 64位整数 | 存储时间戳、ID、计数等大范围整数。支持范围查询、排序、聚合。 |
| integer | 32位整数 | 存储较小范围的整数,如数量、等级等。支持范围查询、排序、聚合。 |
| float/double | 单精度/双精度浮点数 | 存储金额、权重、评分等带小数的数值。支持范围查询、排序、聚合。 |
| boolean | 布尔值,true 或 false | 存储二元状态,如开关、是否激活等。支持过滤和聚合。 |
| date | 日期时间类型 | 存储日期时间,支持多种格式。方便时间范围查询、排序和时间聚合。 |
| binary | 二进制数据,不支持检索和聚合 | 存储图片、文件等二进制内容,主要用于存储,不用于搜索。 |
| 类型 | 说明 | 适用场景与特点 |
|---|---|---|
| object | JSON 对象,包含多个字段 | 存储结构化数据,字段之间无独立索引,数组中对象匹配可能出现跨对象匹配问题。 |
| nested | 嵌套对象数组,每个对象独立索引 | 解决数组中对象字段交叉匹配问题,适合复杂数组结构,支持嵌套查询。 |
| array | Elasticsearch 不单独定义数组类型,字段可直接存储数组值 | 支持存储同类型多个值,数组中元素类型由字段类型决定。 |
| 类型 | 说明 | 适用场景与特点 |
|---|---|---|
| geo_point | 经纬度坐标点 | 存储地理位置点,支持基于距离的查询和排序。 |
| geo_shape | 复杂地理形状,如多边形、线等 | 适合存储区域边界、路径等复杂地理信息,支持空间关系查询。 |
| 类型 | 说明 | 适用场景与特点 |
|---|---|---|
| ip | IPv4 或 IPv6 地址 | 存储IP地址,支持范围查询。 |
| completion | 自动补全建议字段 | 用于实现搜索自动补全功能。 |
| token_count | 统计字符串中词条数量 | 用于分析文本长度或复杂度。 |
| murmur3 | 哈希值字段 | 用于快速哈希计算和索引。 |
| percolator | 存储查询以便反向匹配文档 | 实现基于查询的索引反向匹配。 |
| 类型 | 分词情况 | 支持排序/聚合 | 适用查询类型 | 典型用途 |
|---|---|---|---|---|
| text | 分词 | 不支持排序 | match、全文检索、模糊查询 | 文章内容、评论、描述等长文本 |
| keyword | 不分词 | 支持排序/聚合 | term、精确匹配、过滤 | 用户名、标签、状态、ID等 |
Elasticsearch 5.x 以后,
string类型被拆分为text和keyword,分别满足全文检索和精确匹配需求[2][3][5]。
根据数值大小和精度选择合适类型:
| 类型 | 说明 | 典型范围/用途 |
|---|---|---|
| byte | 8位整数 | -128 到 127 |
| short | 16位整数 | -32,768 到 32,767 |
| integer | 32位整数 | -2^31 到 2^31-1 |
| long | 64位整数 | 大整数,如时间戳、ID |
| float | 单精度浮点数 | 金额、评分等带小数数据 |
| double | 双精度浮点数 | 高精度小数 |
| scaled_float | 通过缩放因子存储浮点数 | 节省存储空间,适合定点数存储 |
text,结构化精确匹配用 keyword。object 或 nested,后者支持嵌套查询,避免字段跨对象匹配错误。合理选择字段类型,是 Elasticsearch 索引设计的关键,直接影响查询性能和存储效率[1][2][3][4][5]。
[1] https://cloud.tencent.com/developer/article/2357713
[2] https://xiaoxiami.gitbook.io/elasticsearch/ji-chu/mapping/zi-duan-de-shu-ju-lei-xing
[3] https://www.cnblogs.com/tanghaorong/p/16323253.html
[4] https://cloud.tencent.com/developer/article/2260312
[5] https://developer.aliyun.com/article/969878
[6] https://blog.csdn.net/aben_sky/article/details/121515175
[7] https://www.cnblogs.com/shoufeng/p/10692113.html
[8] https://blog.csdn.net/ZYC88888/article/details/83059040
[9] https://developer.aliyun.com/article/707773
这是一个非常经典并且常常被误解的数据库优化问题。
简短的回答是:这个说法不完全正确。 更准确地说,它是一个需要根据具体情况分析的优化建议,而不是一个绝对的规则。
下面我将详细解释“为什么会有这个说法”以及“什么时候应该或不应该加索引”。
这个建议的核心在于一个概念:索引的基数(Cardinality)。
user_id, email。status (‘pending’, ‘approved’, ‘rejected’),gender (‘male’, ‘female’, ‘other’),is_active (true, false)。ENUM 和 BOOLEAN 类型天生就是低基数的。低基数列作为索引的主要问题是“筛选效率低下”:
索引选择性差 (Poor Selectivity)
数据库优化器在决定是否使用索引时,会评估其“选择性”。一个好的索引应该能帮你快速排除掉大部分不符合条件的数据。
举个例子:
假设一个 orders 表有1000万条记录,其中 status 列有3个值:’processing’, ‘shipped’, ‘completed’。
SELECT * FROM orders WHERE status = 'shipped';status = 'shipped' 的记录可能占了总数的三分之一,也就是大约333万条。索引维护成本 (Maintenance Overhead)
索引不是免费的。每次对表进行 INSERT, UPDATE, DELETE 操作时,如果动到了索引列,数据库也需要同步更新索引本身。对于一个写操作频繁的表,一个几乎用不上的低效索引反而会拖慢整体的写入性能。
结论: 当一个索引不能有效地区分数据时,它的存在就弊大于利。这就是“不要给低基数列加索引”这个建议的根本原因。
虽然低基数索引通常是低效的,但在以下几种情况下,给它们建立索引却是非常明智和高效的:
数据分布极不均衡 (Skewed Data Distribution)
这是最常见也最重要的例外情况。虽然列的基数很低,但如果某个值的出现频率极低,为它建索引就非常有用。
举例:
一个 users 表有1亿用户,有一个 is_banned (true/false) 字段。
is_banned 是 false。is_banned 是 true(被封禁的用户)。SELECT * FROM users WHERE is_banned = true; 这个查询的选择性就极高。索引可以快速定位到那一小部分被封禁的用户,性能会远超全表扫描。作为覆盖索引 (Covering Index) 的一部分
当一个查询所需的所有列都包含在索引中时,数据库引擎就无需回表,可以直接从索引中获取所有数据返回。这被称为“覆盖索引”。
举例:
你想统计每种订单状态的数量:SELECT status, COUNT(*) FROM orders GROUP BY status;
status 列上建立一个索引 INDEX(status)。status 索引,而完全不需要触碰庞大的主表数据,就能完成统计。这会带来巨大的性能提升。作为复合索引 (Composite Index) 的一部分
当低基数列是复合索引的非前导列时,它通常是非常有用的。
举例:
你的查询条件通常是 WHERE corp_id = ? AND status = ?。
corp_id 是一个高基数列(有很多公司)。status 是一个低基数列。INDEX(corp_id, status) 是非常高效的。corp_id 快速筛选出很少一部分数据,然后再在这个小范围内根据 status 进行查找。此时 status 的低基数问题就不再是瓶颈。| 场景 | 是否建议加索引 | 原因 |
|---|---|---|
| 单独查询,且数据均匀分布 | 不建议 | 索引选择性差,优化器可能放弃使用,且有维护成本。 |
| 单独查询,但数据分布极不均衡 | 强烈建议 | 对稀有值的查询效率极高。 |
| 查询只涉及该列和少数几列 | 建议 | 可以创建覆盖索引,避免回表,极大提升性能。 |
| 作为复合索引的一部分,与其他高选择性列组合 | 强烈建议 | 复合索引可以大大提高多条件查询的效率。 |
实践法则:
SELECT status, COUNT(*) FROM your_table GROUP BY status; 来了解值的分布情况。EXPLAIN:在你认为需要加索引的查询前加上 EXPLAIN,看看数据库的执行计划。确认它是否会使用你创建的索引(key 列),以及扫描的行数(rows 列)是否显著减少。总而言之,“不要给ENUM/低基数列加索引”是一个有用的“经验法则”,它提醒我们警惕低基数列的索引陷阱。但它绝不是一条必须遵守的铁律。 真正的数据库优化需要结合具体业务场景、查询模式和数据分布来进行综合判断。
MySQL表添加业务唯一性约束(Unique Constraint)通常是正确且非常推荐的做法。
这不仅仅是数据库层面的一个设置,更是保证业务逻辑严谨性和数据完整性的关键手段。
NULL 值的处理NULL 值。因为在索引层面,NULL 被认为是一个不确定的值,NULL 不等于任何值,包括另一个NULL。如果你希望某个字段要么唯一,要么为空,那么 UNIQUE 约束是合适的。结论是:应该加。在设计表结构时,应该主动思考哪些字段或字段组合是业务上的“天然唯一标识”,并为它们添加 UNIQUE 约束。