很多介绍es的文章,都会说一下lucene的不足,其中两条有迷惑:

1. lucene的document没有全局唯一的主键id

2. lucene不支持更新。

疑惑点1:没有主键id。

可以用lucene的search接口完成搜索的时候,分两步:1. 获得召回的documentid。2.根据docuemntId获得document的详情

 TopDocs topDocs = searcher.search(queryParser.parse(gap), 10);    #1System.out.println(topDocs.totalHits);for (ScoreDoc doc : topDocs.scoreDocs) {int docId = doc.doc;System.out.println(docId);Document document = searcher.doc(docId);// System.out.println(document);System.out.println(document.get("title"));}

这tm不是docId是啥,根据这个id能够唯一获得对应document的详情,凭啥不唯一,很迷。

首先明确下:能够作为主键id的条件(非官方,个人意见):1.唯一。2.不变。唯一好理解,就是每个document的id应该不一样,没啥说的。不变就是说如果id=12345是document1的主键id,那么只要document没删除,那么id=12345对应的document一定是documment1,不会是其他document。

lucene中的这里的docId(这么叫不准确,官方文档叫document number,截图是源码中),他是段内唯一,不是全局唯一

也就是说,随着段合并,这玩意会改变。它没法用来当全局主键。这么一说可能更疑惑了,搜索的时候刚进行到第一步(代码中的#1)处,然后docId变了,我特么还怎么拿到document的详情,岂不是乱了。初始化IndexSearcher的时候,实际上搜索范围就固定了,就是当前快照,往后索引的改变,通过这个IndexSearcher是查不到的(在使用ES的时候别想当然的给SearchRequest搞个单例)。

从另一个方面看,lucene的接口中,没有根据docId获得document的接口,也没有根据docId更新的接口。

杠精:我找到根据docId获得document的接口,接口如下(IndexReader中,IndexSearcher的doc()方法最终调用的是这个方法)。这不就是搜索第二步调的接口么。没有第一部,你能调用这个接口么?根本就不知道这个docId是个啥。

/*** Returns the stored fields of the <code>n</code><sup>th</sup>* <code>Document</code> in this index.  This is just* sugar for using {@link DocumentStoredFieldVisitor}.* <p>* <b>NOTE:</b> for performance reasons, this method does not check if the* requested document is deleted, and therefore asking for a deleted document* may yield unspecified results. Usually this is not required, however you* can test if the doc is deleted by checking the {@link* Bits} returned from {@link MultiFields#getLiveDocs}.** <b>NOTE:</b> only the content of a field is returned,* if that field was stored during indexing.  Metadata* like boost, omitNorm, IndexOptions, tokenized, etc.,* are not preserved.* * @throws CorruptIndexException if the index is corrupt* @throws IOException if there is a low-level IO error*/// TODO: we need a separate StoredField, so that the// Document returned here contains that class not// IndexableFieldpublic final Document document(int docID) throws IOException {final DocumentStoredFieldVisitor visitor = new DocumentStoredFieldVisitor();document(docID, visitor);return visitor.getDocument();}

疑惑点2:lucene不支持部分更新

杠精:IndexWriter找到update接口一枚。

/*** Updates a document by first deleting the document(s)* containing <code>term</code> and then adding the new* document.  The delete and then add are atomic as seen* by a reader on the same index (flush may happen only after* the add).** @return The <a href="#sequence_number">sequence number</a>* for this operation** @param term the term to identify the document(s) to be* deleted* @param doc the document to be added* @throws CorruptIndexException if the index is corrupt* @throws IOException if there is a low-level IO error*/public long updateDocument(Term term, Iterable<? extends IndexableField> doc) throws IOException {ensureOpen();try {boolean success = false;try {long seqNo = docWriter.updateDocument(doc, analyzer, term);if (seqNo < 0) {seqNo = - seqNo;processEvents(true, false);}success = true;return seqNo;} finally {if (!success) {if (infoStream.isEnabled("IW")) {infoStream.message("IW", "hit exception updating document");}}}} catch (AbortingException | VirtualMachineError tragedy) {tragicEvent(tragedy, "updateDocument");// dead code but javac disagrees:return -1;}}

细看接口描述确实可以更新,条件是Term+Field,即将那些包含该term的document的对应字段都更新成指定值,所以说它实际是个term query+update,而且,这根本不是更新,而是新建,是将满足term的给删了,然后新建一个指定的docment。但是它原生并不能支持像mysql的update一样的部分更新操作。

从这个角度看,lucene不能支持更新的两个原因:1. 没有全局唯一的主键id。2. lucene中没有存储完整的文档原始内容(即使有个stored属性,它也是字段级别的,还是可选的,没法保证docuemnt的原始内容),没有原始数据,就不能够进行部分更新。

es解决这个问题就是加了_id和_source字段。

ES的做法

每个文档都会默认有两个字段:_id,_source.

_id是全局唯一的(not_ananlyzed),如果客户端不指定,es生成一个默认的;如果指定不唯一,则索引文档的时候就报错。

_source(stored=true)将document的所有字段值以json的格式存储在该字段中。

注意:凡是要基于document的原始内容的操作,如部分更新,rebuild接口,script脚本等,这些都要保证没有禁用_source字段,否则会出现问题。

其实根据上面的描述也不用多说这两个字段怎么实现局部更新的。

注:elasticsearch新人,以上内容纯粹是自己学习过程中遇到的疑惑,"杠精"就是我当时的真实想法。不正确或者不准确的地方,希望大神留言指针,我将多多学习。

es中document的主键id及局部更新相关推荐

  1. mysql中在表中insert数据时,有重复主键id时,变成update

    MySQL 自4.1版以后开始支持INSERT - ON DUPLICATE KEY UPDATE语法 例如:  id name sex age  1 kathy male 23  2 Javer f ...

  2. python 类 实例id递增_Python Django 模板类中 系统默认的主键ID自增,不会随着模板实例的删除而重置问题...

    题目描述 在django中创建两个模板实例后,删除后重新再创建一个模板实例后它的主键ID从3开始这是为什么? 怎样解决这个问题? 相关代码 modeles类: from django.db impor ...

  3. 获取GridView中RowCommand的当前选中行的索引或主键Id

    获取GridView中RowCommand的当前索引行 前台添加一模版列,里面添加一个LinkButton 前台 (如果在后台代码中用e.CommandArgument取值的话前台代码就必须在按钮中设 ...

  4. oracle和mybatis自增,在Springboot项目中使用MybatisPlus和Oracle实现主键ID的自增

    在Springboot项目中使用MybatisPlus和Oracle实现主键ID的自增 发布时间:2020-11-18 15:49:35 来源:亿速云 阅读:125 作者:Leah 在Springbo ...

  5. 主键ID是什么,做什么用的?(能够唯一表示数据表中的每个记录,防止数据冲突,冗余)

    能够唯一表示数据表中的每个记录的[字段]或者[字段]的组合就称为主码(主键). 作用 1.主键唯一的识别每一记录; 2.主键将记录和存放在其他表中的数据进行关联.在这一点上,主键是不同表中各记录之间的 ...

  6. python mysql批量insert数据、返回id_Python3 操作 MySQL 插入一条数据并返回主键 id的实例...

    Python 中貌似并没有直接返回插入数据 id 的操作(反正我是没找到),但是我们可以变通一下,找到最新插入的数据 #!/usr/bin/env python3 # -*- coding: UTF- ...

  7. mybatis添加记录时返回主键id

    参考:mybatis添加记录时返回主键id 场景 有些时候我们在添加记录成功后希望能直接获取到该记录的主键id值,而不需要再执行一次查询操作. 在使用mybatis作为ORM组件时,可以很方便地达到这 ...

  8. mysql自增字段不连续_MySQL中自增主键不连续之解决方案。(20131109)

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 今天只做了一件事情,但解决了很大的问题.相信这也是令很多程序员和数据库管理员头疼的事情. 假设在一MySQL数据表中,自增的字段为id,唯一字段为abc, ...

  9. MyBatis在insert插入操作时返回主键ID

    数据库为MySql时:  <insert id="insert" parameterType="com.test.User" keyProperty=&q ...

最新文章

  1. python怎么学最快-零基础怎么样才能学好Python?Python入门必看
  2. JS创建对象学习笔记
  3. 如何制定项目工作计划
  4. java遍历对象属性_java开发中遍历一个对象的所有属性并set值 缓存优化
  5. 废旧光盘手工小制作_废旧利用 | 幼儿园手工卷纸筒制作大全,超实用
  6. Hawq超过最大允许连接数
  7. 微信小程序四(设置底部导航)
  8. java 排序经典算法,经典排序算法(java版)
  9. mysql 数据库军规_用尽洪荒之力整理的Mysql数据库32条军规(转)
  10. 获取oracle日志文件,ORACLE关于日志文件基本操作
  11. Codeforces Round #612 (Div. 2) A~E2
  12. UCINET软件使用简介——主菜单简介2
  13. PDF怎么裁剪页面,PDF裁剪页面的方法
  14. 计算机桌面ie图标无法删除,桌面IE浏览器图标无法删除怎么办
  15. 国庆七天乐,要猛! ——经典迷宫问题
  16. ant design vue时间范围(range-picker)自定义时间段范围
  17. 第1章第7节:如何通过大纲级别批量创建幻灯片 [PowerPoint精美幻灯片实战教程]
  18. hive指标计算:同比
  19. Android 资源文件错误排查 Process 'command ' 等错误排查
  20. 基金 、社保和QFII等机构的重仓股排名评测

热门文章

  1. Vue组件通讯的多种方式(个人记录)
  2. MOSFET和IGBT栅极驱动器电路的基本原理的学习(1)
  3. Proxy与Reflect详解
  4. 如何修改文件的扩展名(后缀)
  5. 利用curl进行ftp的下载和上传
  6. [1]数据分析中变量取对数的意义
  7. 科技文章也可以非常的文采对立统一描述的简洁明了
  8. 简练软考知识点整理-规划进度管理
  9. 这4个正经的网站,能看片还能涨知识!
  10. Integrated Product Development