Elasticsearch - 文档分析,IK分词器;文档冲突(十二)

article/2025/8/23 13:24:18

阅读本文前可先参考

Elasticsearch - Elasticsearch详解;安装部署(一)_MinggeQingchun的博客-CSDN博客

https://blog.csdn.net/MinggeQingchun/article/details/126855747

一、文档分析

文档分析过程如下:

1、将一块文本分成适合于倒排索引的独立的 词条

2、将这些词条统一化为标准格式以提高它们的“可搜索性”,或者 recall

分析器执行上面的工作,实际是将三个功能封装到一个包里

一个 分析器 就是在一个包里面组合了三种函数的一个包装器, 三种函数按照顺序被执行

1、字符过滤器

首先,字符串按顺序通过每个 字符过滤器 。他们的任务是在分词前整理字符串。一个字符过滤器可以用来去掉 HTML,或者将 & 转化成 and

2、分词器

其次,字符串被 分词器 分为单个的词条。一个简单的分词器遇到空格和标点的时候,可能会将文本拆分成词条(一个分析器 必须 有一个唯一的分词器

3、Token 过滤器

最后,词条按顺序通过每个 token 过滤器 。这个过程可能会改变词条(如,小写化Quick ),删除词条(如,像 a,and,the 等无用词),或者增加词条(如,像 jump 和 leap 这种同义词)

(一)内置分析器

Elasticsearch 附带了可以直接使用的预包装的分析器

验证每个分析器会从如下的字符串得到哪些词条:

"Set the shape to semi-transparent by calling set_trans(5)"

1、标准分析器

标准分析器是 Elasticsearch 默认使用的分析器。它是分析各种语言文本最常用的选择。它根据 Unicode 联盟 定义的 单词边界 划分文本。删除绝大部分标点。最后,将词条小写。

它会产生:

set, the, shape, to, semi, transparent, by, calling, set_trans, 5

2、简单分析器

简单分析器在任何不是字母的地方分隔文本,将词条小写。

它会产生:

set, the, shape, to, semi, transparent, by, calling, set, trans

3、空格分析器

空格分析器在空格的地方划分文本。

它会产生:

Set, the, shape, to, semi-transparent, by, calling, set_trans(5)

4、语言分析器

特定语言分析器可用于 很多语言。它们可以考虑指定语言的特点。如, 英语分析器附带了一组英语无用词(常用单词,例如 and 或者 the ,它们对相关性没有多少影响),它们会被删除。 由于理解英语语法的规则,这个分词器可以提取英语单词的 词干。

英语 分词器会产生下面的词条:

set, shape, semi, transpar, call, set_tran, 5

测试:

Postman中发送GET请求:http://localhost:9200/_analyze

{"analyzer": "standard","text": "Text to analyze"
}

每个元素代表一个单独的词条 

token 是实际存储到索引中的词条

position 指明词条在原始文本中出现的位置

start_offset 和 end_offset 指明字符在原始字符串中的位置

(二)分析器使用场景

当我们 索引 一个文档,它的全文域被分析成词条以用来创建倒排索引。 但是,当我们在全文域 搜索 的时候,我们需要将查询字符串通过 相同的分析过程 ,以保证我们搜索的词条格式与索引中的词条格式一致

全文查询,理解每个域是如何定义的,因此它们可以做正确的事:

(1)查询一个 全文 域时, 会对查询字符串应用相同的分析器,以产生正确的搜索词条列表

(2)查询一个 精确值 域时,不会分析查询字符串,而是搜索你指定的精确值

(三)IK分词器

ES 的默认分词器无法识别中文中测试、单词这样的词汇,而是简单的将每个字拆完分为一 个词

 采用IK分词器

下载地址:

https://github.com/medcl/elasticsearch-analysis-ik/releases

找到对应版本下载,如

将解压后的后的文件夹放入 ES 根目录下的 plugins 目录下,重启 ES 即可使用 

1、ik_max_wordik_smart

加入新参数:"analyzer":"ik_max_word"

{
"text":"测试单词",
"analyzer":"ik_max_word"
}

ik_max_word:会将文本做最细粒度的拆分

ik_smart:会将文本做最粗粒度的拆分

2、扩展词 

(1)首先进入 ES 根目录中的 plugins 文件夹下的 ik 文件夹,进入 config 目录,创建 custom.dic 文件,写入"测试单词"

(2)打开 IKAnalyzer.cfg.xml 文件,将新建的 custom.dic 配置其中, 重启 ES 服务器

再次测试

(四)自定义分析器 

1、自定义分析器

发送PUT请求 http://localhost:9200/my_index

{"settings":{"analysis":{"char_filter":{"&_to_and":{"type":"mapping","mappings":["&=> and "]}},"filter":{"my_stopwords":{"type":"stop","stopwords":["the","a"]}},"analyzer":{"my_analyzer":{"type":"custom","char_filter":["html_strip","&_to_and"],"tokenizer":"standard","filter":["lowercase","my_stopwords"]}}}}
}

索引创建好,使用 analyze API 测试分析器

发送GET请求 http://127.0.0.1:9200/my_index/_analyze

{"text":"The cat & brown fox","analyzer": "my_analyzer"
}

 

二、文档冲突

1、文档冲突

当我们使用 index API 更新文档 ,可以一次性读取原始文档,做修改,然后重新索引 整个文档 。 最近的索引请求将获胜:无论最后哪一个文档被索引,都将被唯一存储在 Elasticsearch 中。如果其他人同时更改这个文档,他们的更改将丢失。变更越频繁,读数据和更新数据的间隙越长,也就越可能丢失变更。

常见的场景:如火车票销售余票数量,商品销售库存数量等

在数据库领域中,有两种方法通常被用来确保并发更新时变更不会丢失:

(1)悲观并发控制

这种方法被关系型数据库广泛使用,它假定有变更冲突可能发生,因此阻塞访问资源以防止冲突。 一个典型的例子是读取一行数据之前先将其锁住,确保只有放置锁的线程能够对这行数据进行修改

(2)乐观并发控制

Elasticsearch 中使用的这种方法假定冲突是不可能发生的,并且不会阻塞正在尝试的操作。 然而,如果源数据在读写当中被修改,更新将会失败。应用程序接下来将决定该如何解决冲突。 如:可以重试更新、使用新的数据、或者将相关情况报告给用户

2、乐观并发控制

Elasticsearch 是分布式的。当文档创建、更新或删除时, 新版本的文档必须复制到集群中的其他节点。

Elasticsearch 也是异步和并发的,文档复制请求被并行发送,并且到达目的地时,也许顺序是乱的。Elasticsearch 需要一种方法确保文档的旧版本不会覆盖新的版本

测试index 的 GET 和 delete 请求时,每个文档都有一个 _version (版本)号,当文档被修改时版本号递增。 Elasticsearch 使用这个 version 号来确保变更以正确顺序得到执行。如果旧版本的文档在新版本之后到达,它可以被简单的忽略

我们可以利用 version 号来确保 应用中相互冲突的变更不会导致数据丢失。我们通过 指定想要修改文档的 version 号来达到这个目的。 如果该版本不是当前版本号,我们的请求将会失败

注:

老的版本 es 使用 version,但是新版本不支持了,会报下面的错误,提示我们用 if_seq_noif_primary_term

_seq_no:文档版本号,作用同_version(相当于学生编号,每个班级的班主任为学生分配编号,效率要比学校教务处分配来的更加高效,管理起来更方便)

_primary_term:文档所在位置(相当于班级)

官网文档:

ES之4:Elasticsearch并发控制及乐观锁实现原理_mb5fdb1266ce6df的技术博客_51CTO博客

发送POST请求,http://127.0.0.1:9200/shopping/_update/1?version=1

{ "doc": {"price":3000.00} 
}

报错如下:

{"error": {"root_cause": [{"type": "action_request_validation_exception","reason": "Validation Failed: 1: internal versioning can not be used for optimistic concurrency control. Please use `if_seq_no` and `if_primary_term` instead;"}],"type": "action_request_validation_exception","reason": "Validation Failed: 1: internal versioning can not be used for optimistic concurrency control. Please use `if_seq_no` and `if_primary_term` instead;"},"status": 400
}

重新发送POST请求: http://127.0.0.1:9200/shopping/_update/1?if_seq_no=1&if_primary_term=1

{ "doc": {"price":3000.00} 
}

就会修改成功 

 如果携带旧版本号 seq_no,就会报错冲突

[1]: version conflict, required seqNo [1], primary term [1]. current document has seqNo [2] and primary term [1]

{"error": {"root_cause": [{"type": "version_conflict_engine_exception","reason": "[1]: version conflict, required seqNo [1], primary term [1]. current document has seqNo [2] and primary term [1]","index_uuid": "_Ks_veihS4Ga8eh0hl24eA","shard": "0","index": "shopping"}],"type": "version_conflict_engine_exception","reason": "[1]: version conflict, required seqNo [1], primary term [1]. current document has seqNo [2] and primary term [1]","index_uuid": "_Ks_veihS4Ga8eh0hl24eA","shard": "0","index": "shopping"},"status": 409
}

3、外部系统版本控制

如果使用其它数据库作为主要的数据存储,使用 Elasticsearch 做数据检 索, 这意味着主数据库的所有更改发生时都需要被复制到 Elasticsearch ,如果多个进程负责这一数据同步,同样会遭遇文档冲突的问题

如果主数据库已经有了版本号 或一个能作为版本号的字段值,如 timestamp; 那么你就可以在 Elasticsearch 中通过增加 version_type=external 到查询字符串的方式重用这些相同的版本号, 版本号必须是大于零的整数, 且小于 9.2E+18 ( 一个 Java 中 long类型的正值)

外部版本号的处理方式和内部版本号的处理方式有些不同,Elasticsearch 不是检查当前 _version 和请求中指定的版本号是否相同, 而是检查当前 _version 是否 小于 指定的版本号。 如果请求成功,外部的版本号作为文档的新 _version 进行存储

外部版本号不仅在索引和删除请求是可以指定,而且在 创建 新文档时也可以指定

首先查看文档:http://127.0.0.1:9200/shopping/_doc/1

发送POST请求:http://127.0.0.1:9200/shopping/_doc/1?version=3&version_type=external

 

 如果发送version小于1 的版本就会报错

{"error": {"root_cause": [{"type": "version_conflict_engine_exception","reason": "[1]: version conflict, current version [3] is higher or equal to the one provided [1]","index_uuid": "_Ks_veihS4Ga8eh0hl24eA","shard": "0","index": "shopping"}],"type": "version_conflict_engine_exception","reason": "[1]: version conflict, current version [3] is higher or equal to the one provided [1]","index_uuid": "_Ks_veihS4Ga8eh0hl24eA","shard": "0","index": "shopping"},"status": 409
}


http://chatgpt.dhexx.cn/article/yIxb7KbS.shtml

相关文章

springboot+Elasticsearch实现word,pdf,txt内容抽取并高亮分词全文检索

文章目录 需求 一、环境 二、功能实现 1.搭建环境 2.文件内容识别 三.代码 需求 产品希望我们这边能够实现用户上传PDF,WORD,TXT之内得文本内容,然后用户可以根据附件名称或文件内容模糊查询文件信息,并可以在线查看文件内容 一、环境 项目开发环境&…

使用lucce分词怎么_ElasticSearch 分词器,了解一下

这篇文章主要来介绍下什么是 Analysis ,什么是分词器,以及 ElasticSearch 自带的分词器是怎么工作的,最后会介绍下中文分词是怎么做的。 首先来说下什么是 Analysis: 什么是 Analysis? 顾名思义,文本分析就…

自然语言处理 # 中文分词技术 概述

定义 中文分词(Chinese Word Segmentation)就是将连续的字序列按照一定的规范重新组合成词序列的过程。 Ques:为什么要分词? Ans: 词是最小的能够独立运用的语言单位 Ques:什么是独立运用呢? Ans:它可以解释为“单独做句法成分或…

Python 中 concurrent.futures 模块使用说明

Python 中 concurrent.futures 模块使用说明 转载请注明出处:https://blog.csdn.net/jpch89/article/details/87643972 文章目录 Python 中 concurrent.futures 模块使用说明0. 参考资料1. 概述2. Executor Object 执行器对象3. ThreadPoolExecutor 线程池执行器4.…

【ruoyi】java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.ScheduledThreadPoo

前言 ruoyi 4.6.0jdk1.8 错误 11:48:16.879 [http-nio-9031-exec-25] INFO c.r.f.s.r.UserRealm - [doGetAuthenticationInfo,128] - 对用户[admin]进行登录验证..验证未通过{} java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.ScheduledThre…

【学习积累】Queue 与 ConcurrentQueue性能测试

在 C# 中&#xff0c;关于队列&#xff08;Queue&#xff09;有两种&#xff0c;一种就是我们普通使用的队列&#xff0c;另一种是线程安全的队列 ConcurrentQueue<T> 。 ConcurrentQueue表示线程安全的先进先出 (FIFO) 集合。https://learn.microsoft.com/zh-cn/dotnet…

Python报错ModuleNotFoundError: No module named ‘concurrent‘

在测试Python的多线程时&#xff0c;根据官方的说法&#xff0c;concurrent.futures在Python3中已经内置了&#xff0c;不需要下载安装&#xff0c;如果是Python2则需要运行pip install futures进行安装。。。 这样导入&#xff0c;两种写法均可 import concurrent.futures #…

go语言工具_Concurrent Map

Concurrent Map 背景 map是平时项目中经常用到的数据类型&#xff0c;但是如果多个协程去读写同一个map时&#xff0c;为了不发生数据错误&#xff0c;经常去将其和锁封装成一个新的map。像以下两种示例。 type LockMap struct { m map[interface{}]interface{} l…

C#线程安全队列ConcurrentQueue

ConcurrentQueue成员函数 入队(EnQueue) 、出队(TryDequeue) 、是否为空(IsEmpty)、获取队列内元素数量(Count)。 void Enqueue(T item) 入队函数&#xff0c;当队列已满时会自动增加队列容量。 bool TryDequeue(T* result) 尝试移除并返回并发队列开头处对象&#xff0c;…

项目优化>C++,concurrentqueue(高性能并发队列)

项目中的数据队列基于轮询和selep的实时性及CUP性能差&#xff0c;需要进行优化&#xff0c;尝试使用concurrentqueue进行优化。网上有一些资料介绍,可供参考。 使用后的个人理解:一个线程安全的queue&#xff0c;并且concurrentqueue的线程安全并不是一味的加锁&#xff0c;它…

ConcurrentMap

ConcurrentMap&#xff0c;它是一个接口&#xff0c;是一个能够支持并发访问的java.util.map集合&#xff1b; ConcurrentHashMap是一个线程安全&#xff0c;并且是一个高效的HashMap。 spring 缓存注解 通过查看源代码发现将数据存在ConcurrentMap中 1 Map并发集合 1.1 Co…

学习线程安全队列ConcurrentQueue

首先,基本使用&#xff1a;入队(EnQueue) 、出队(TryDequeue) 、是否为空(IsEmpty)、获取队列内元素数量(Count)。 一、ConcurrentQueue内部结构: 1.实现原理 众所周知&#xff0c;在普通的非线程安全队列有两种实现方式: 1.使用数组实现的循环队列。 2.使用链表实现的队列…

并发系列(六)-----concurrent的简单介绍

一 简介 concurrent包是jdk1.5引入的重要的包&#xff0c;主要代码由大牛Doug Lea完成。这个包下的一些类如果用好了可以很方便的保证数据在多线程下操作的正确性。就比如说线程共享的i&#xff0c;如果使用concurrent包下的Atomic系列类可以很方便的解决这个问题。这篇文章简单…

python并发之concurrent快速入门

导读&#xff1a;我很笨&#xff0c;但是我很快——计算机之所以计算能力如此出众&#xff0c;不在于其有多智能&#xff0c;而是因为它超快的执行速度&#xff0c;而多核心则可以进一步成倍的提高效率。在python中&#xff0c;concurrent库就是用于完成并发的模块之一。 01 初…

Java 并发工具包(concurrent)详解

目录 一、concurrent并发包 二、ReentrantLock&#xff08;可重入锁&#xff09; 1、锁状态中断与可重入 2、尝试非阻塞地获取锁 3、等待可中断 4、设置公平锁 三、CountDownLatch&#xff08;门栓&#xff09; 四、cyclicBarrier&#xff08;栅栏&#xff09; 五、…

JAVA中split函数的用法

JAVA中split函数的用法 只写经常使用的&#xff0c;并不完整。 1.基本用法&#xff0c;将字符串按照指定字符串进行分割&#xff0c;例如&#xff1a; public class Main {public static void main(String[] args) {String ss "abcabcdefg";String[] split ss.sp…

C语言实现split函数

实现类似JAVA编程语言中split函数&#xff1a; &#xff08;这里以空格为分隔符进行演示&#xff09; 函数的声明&#xff1a;void split(char *src,const char *separator,char **dest,int *num) {}变量&#xff1a; 1.*src&#xff1a;要进行分割的字符串地址&#xff0c; 2…

mysql实现自定义split函数

1、自定义split函数脚本 CREATE DEFINER root% FUNCTION tjdemo.fun_get_split_string_total(f_string varchar(1000),f_delimiter varchar(5)) RETURNS int(11) LANGUAGE SQL NOT DETERMINISTIC CONTAINS SQL SQL SECURITY DEFINER COMMENT BEGIN declare returnInt int(11…

Oracle实现split函数

创建TYPE CREATE OR REPLACE TYPE TYPE_SPLIT AS TABLE OF VARCHAR2 (4000);创建函数 CREATE OR REPLACE FUNCTION SPLIT(P_STRING VARCHAR2, P_SEP VARCHAR2 : ,)RETURN TYPE_SPLITPIPELINED ISIDX PLS_INTEGER;V_STRING VARCHAR2(4000) : P_STRING; BEGINLOOPIDX : INSTR(…

java split函数的用法_java中split函数用法以及注意事项

java中split函数用法以及注意事项 发布时间&#xff1a;2020-04-23 10:28:23 来源&#xff1a;亿速云 阅读&#xff1a;215 作者&#xff1a;小新 本篇文章和大家了解一下java中split函数用法以及注意事项。有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希…