四、初探[ElasticSearch]集群架构原理与搜索技术

目录

  • 一、浅析Elasticsearch架构原理
    • 1.Elasticsearch的节点类型
      • 1.1 Master节点
      • 1.2DataNode节点
  • 二、分片和副本机制
    • 2.1分片
    • 2.2副本
    • 2.3指定分片、副本数量
    • 2.4查看分片、主分片、副本分片
  • 三、Elasticsearch工作流程
    • 3.1Elasticsearch文档写入原理
    • 3.2Elasticsearch检索原理
  • 四、Elasticsearch准实时索引实现
    • 4.1溢写到文件系统缓存
    • 4.2写translog保障容错
    • 4.3flush到磁盘(刷盘)
    • 4.4segment合并
  • 五.手动控制搜索结果精准度
    • 5.1operator与minimum_should_match简单使用
    • 5.2、match 的底层转换
    • 5.3、boost权重控制
    • 5.4、基于dis_max实现best fields策略进行多字段搜索
    • 5.5、基于tie_breaker参数优化dis_max搜索效果
    • 5.6、使用multi_match简化dis_max+tie_breaker(不常用)
    • 5.7、cross_fields搜索
    • 5.8、copy_to组合fields
    • 5.9、近似匹配
    • 5.10、match_phrase
      • 5.10.1match phrase原理 —— term position
      • 5.10.2match phrase搜索参数 -- slop
    • 5.11使用match和proximity search实现召回率和精准度平衡。
    • 5.12前缀搜索 prefix search
    • 5.13通配符搜索
    • 5.14正则搜索
    • 5.15搜索推荐
    • 5.16fuzzy模糊搜索技术

一、浅析Elasticsearch架构原理

1.Elasticsearch的节点类型

在Elasticsearch主要分成两类节点,一类是Master,一类是DataNode。

1.1 Master节点

在Elasticsearch启动时,会选举出来一个Master节点。采用Zen Discovery1机制选出master节点并且找到集群中的其他节点,并建立连接。一个Elasticsearch集群中,只有一个Master节点。(这里的一个是在集群范围中的,而不是指定某台服务器一直就是主节点,主节点所在服务器宕机,其他的某一个节点有机会成为master节点)

Master节点主要功能::

  1. 管理索引和分片的创建、删除和重新分配。
  2. 监测节点的状态,并在需要时进行重分配。
  3. 协调节点之间的数据复制和同步工作。
  4. 处理集群级别操作,如创建或删除索引、添加或删除节点等。
  5. 维护集群的健康状态,并在集群出现问题时采取措施解决。
  6. 维护元数据2

1.2DataNode节点

与master节点不同,datanode节点可能会有多个。这个取决于你集群的节点数量,因为master在集群中只能有一个,其余为DataNode节点。
DataNode节点主要功能:

  1. 存储和索引数据:Data Node 节点会将索引分片存储在本地磁盘上,并对查询请求进行响应。
  2. 复制和同步数据:为了确保数据的可靠性和高可用性,ElasticSearch 会将每个原始分片的多个副本存储在不同的 Data Node 节点上,并定期将各节点上的数据进行同步。
  3. 参与搜索和聚合操作:当客户端提交搜索请求时,Data Node 节点会使用本地缓存和分片数据完成搜索和聚合操作。
  4. 执行数据维护操作:例如,清理过期数据和压缩分片等。

二、分片和副本机制

在第一篇文章中也有介绍过这俩个概念,这里在集群中再次进行解释
在这里插入图片描述

2.1分片

ElasticSearch是一个分布式的搜索引擎,索引索引可以分成一份或多份,多份分片分布在不同节点当中。ElasticSearch会自动管理分片,如果发现分片分布不均衡,就会自动迁移。

2.2副本

在ElasticSearch中每个分片都有一个主分片,可能会有若干个副本分片(默认一个分片,一个副本),这些副本也会分布在不同的节点上。

2.3指定分片、副本数量

PUT /test_index06
{"mappings": {"properties": {"name": {"type": "keyword","index": true,"store": true},................}},//设置分片数量1,副本数量2"settings": {"number_of_shards": 1,"number_of_replicas": 2}
}

2.4查看分片、主分片、副本分片

GET /_cat/indices?v

三、Elasticsearch工作流程

3.1Elasticsearch文档写入原理

在这里插入图片描述

如何知道我插入一条数据要保存到那个分片呢?

shard = hash(routing) % number_of_primary_shards
routing 是一个可变值,默认是文档的 _id。
number_of_primary_shards为分片数量
你也可以使用自己的自定义分片键,只需在索引时指定"_routing"字段即可。

3.2Elasticsearch检索原理

在这里插入图片描述
客户端发起查询请求,某个DataNode接收到请求,该DataNode就会成为协调节点。
协调节点(Coordinating Node)将查询请求广播到每一个数据节点,这些数据节点的分片会处理该查询请求, 每个分片进行数据查询,将符合条件的数据放在一个优先队列中,并将这些数据的文档ID、节点信息、分片信息返回给协调节点。
协调节点将所有的结果进行汇总,并进行全局排序, 协调节点向包含这些文档ID的分片发送get请求,对应的分片将文档数据返回给协调节点,最后协调节点将数据返回给客户端。

四、Elasticsearch准实时索引实现

在这里插入图片描述

4.1溢写到文件系统缓存

当数据写入到ES分片时,会首先写入到内存中,然后通过内存的buffer生成一个segment,并刷到文件系统缓存中,数据可以被检索(注意不是直接刷到磁盘)ES中默认1秒,refresh缓存一次。

4.2写translog保障容错

在写入到内存中的同时,也会记录translog日志,在refresh期间出现异常,会根据translog来进行数据恢复
等到文件系统缓存中的segment数据都刷到磁盘中,清空translog文件。

4.3flush到磁盘(刷盘)

ES默认每隔30分钟会将文件系统缓存的数据刷入到磁盘。

4.4segment合并

Segment太多时,ES定期会将多个segment合并成为大的segment,减少索引查询时IO开销,此阶段ES会真正的物理删除(之前执行过的delete的数据)。

五.手动控制搜索结果精准度

5.1operator与minimum_should_match简单使用

①查询document中的remark字段包含java或developer词组。

GET /test_index05/_search
{"query": {"match": {"remark": "java developer"}}
}

或者这样查询

GET /test_index05/_search
{"query": {"match": {"remark": {"query": "java developer","operator": "or"}}}
}

结果

 "hits" : [{"_index" : "test_index05","_type" : "_doc","_id" : "2","_score" : 0.77041256,"_source" : {"name" : "宝塔镇河妖","sex" : 1,"age" : 25,"address" : "上海","remark" : "java developer"}},{"_index" : "test_index05","_type" : "_doc","_id" : "1","_score" : 0.21110919,"_source" : {"name" : "天王盖地虎","sex" : 1,"age" : 25,"address" : "上海","remark" : "java"}}]

②查询document中的remark字段,同时包含java和developer词组

GET /test_index05/_search
{"query": {"match": {"remark": {"query": "java developer","operator": "and"}}}
}

结果

"hits" : [{"_index" : "test_index05","_type" : "_doc","_id" : "2","_score" : 0.77041256,"_source" : {"name" : "宝塔镇河妖","sex" : 1,"age" : 25,"address" : "上海","remark" : "java developer"}}]

③minimum_should_match可以使用百分比或固定数字。百分比代表query搜索条件中词条百分比,如果无法整除,向下匹配(如,query条件有3个单词,如果使用百分比提供精准度计算,那么是无法除尽的,如果需要至少匹配两个单词,则需要用67%来进行描述。如果使用66%描述,ES则认为匹配一个单词即可)。固定数字代表query搜索条件中的词条,至少需要匹配多少个。
③-1百分比
查询内容包括java 或developer或assistant中匹配度达到66%即文档内容中,至少包括一个单词出现。

GET /test_index05/_search
{"query": {"match": {"remark": {"query": "java developer assistant","minimum_should_match": "66%"}}}
}
"hits" : [{"_index" : "test_index05","_type" : "_doc","_id" : "1","_score" : 0.21110919,"_source" : {"name" : "天王盖地虎","sex" : 1,"age" : 25,"address" : "上海","remark" : "java"}},{"_index" : "test_index05","_type" : "_doc","_id" : "2","_score" : 0.160443,"_source" : {"name" : "宝塔镇河妖","sex" : 1,"age" : 25,"address" : "上海","remark" : "java developer"}}]

查询内容包括java 或architect 或assistant中匹配度达到67%即文档内容中,至少包括两个个单词出现。

GET /test_index05/_search
{"query": {"match": {"remark": {"query": "java developer assistant","minimum_should_match": "67%"}}}
}

结果

"hits" : [{"_index" : "test_index05","_type" : "_doc","_id" : "2","_score" : 0.77041256,"_source" : {"name" : "宝塔镇河妖","sex" : 1,"age" : 25,"address" : "上海","remark" : "java developer"}}]

③-2固定数字
查询的内容中至少出现下面三个条件中的两个,即java、developer、assistant这三个单词,至少有两个同时出现才符合条件。

GET /test_index05/_search
{"query": {"bool": {"should": [{"match": {"remark": "java"}},{"match": {"remark": "developer"}},{"match": {"remark": "assistant"}}],"minimum_should_match": 2}}
}

结果

"hits" : [{"_index" : "test_index05","_type" : "_doc","_id" : "2","_score" : 0.77041256,"_source" : {"name" : "宝塔镇河妖","sex" : 1,"age" : 25,"address" : "上海","remark" : "java developer"}}]

5.2、match 的底层转换

我们输入的查询语句

GET /test_index05/_search
{"query": {"match": {"remark": "java developer"}}
}

转换后的查询语句

GET /test_index05/_search
{"query": {"bool": {"should": [{"term": {"remark": "java"}},{"term": {"remark": {"value": "developer"}}}]}}
}

查询语句

GET /test_index05/_search
{"query": {"match": {"remark": {"query": "java developer","operator": "and"}}}
}

转换后

GET /test_index05/_search
{"query": {"bool": {"must": [{"term": {"remark": "java"}},{"term": {"remark": {"value": "developer"}}}]}}
}

查询条件

GET /test_index05/_search
{"query": {"match": {"remark": {"query": "java developer assistant","minimum_should_match": "68%"}}}
}

转换后

GET /test_index05/_search
{"query": {"bool": {"should": [{"term": {"remark": "java"}},{"term": {"remark": "developer"}},{"term": {"remark": "assistant"}}],"minimum_should_match": 2}}
}

使用转换后的语法执行搜索,效率更高。

5.3、boost权重控制

搜索document中remark字段中包含java的数据,如果remark中包含developer或assistant,则包含assistant的document优先显示。(就是将assistant数据匹配时的相关度分数增加)。
一般用于搜索时相关度排序使用。如:电商中的综合排序。将一个商品的销量,广告投放,评价值,库存,单价比较综合排序。在上述的排序元素中,广告投放权重最高,库存权重最低。还有就是百度搜索内容时前几一般都是广告。

例如
索引test_index05下全部数据为

"hits" : [{"_index" : "test_index05","_type" : "_doc","_id" : "1","_score" : 1.0,"_source" : {"name" : "天王盖地虎","sex" : 1,"age" : 25,"address" : "上海","remark" : "java"}},{"_index" : "test_index05","_type" : "_doc","_id" : "2","_score" : 1.0,"_source" : {"name" : "宝塔镇河妖","sex" : 1,"age" : 25,"address" : "上海","remark" : "java developer"}},{"_index" : "test_index05","_type" : "_doc","_id" : "3","_score" : 1.0,"_source" : {"name" : "铁锅炖大鹅","sex" : 1,"age" : 19,"address" : "天津","remark" : "java assistant"}}]

查询(boost越高,表示权重越高,越优先展示)

GET /test_index05/_search
{"query": {"bool": {"must": [{"match": {"remark": "java"}}],"should": [{"match": {"remark": {"query": "developer","boost": 1}}},{"match": {"remark": {"query": "assistant","boost": 3}}}]}}
}

结果

"hits" : [{"_index" : "test_index05","_type" : "_doc","_id" : "3","_score" : 2.3016074,"_source" : {"name" : "铁锅炖大鹅","sex" : 1,"age" : 19,"address" : "天津","remark" : "java assistant"}},{"_index" : "test_index05","_type" : "_doc","_id" : "2","_score" : 1.474477,"_source" : {"name" : "宝塔镇河妖","sex" : 1,"age" : 25,"address" : "上海","remark" : "java developer"}},{"_index" : "test_index05","_type" : "_doc","_id" : "1","_score" : 0.43250346,"_source" : {"name" : "天王盖地虎","sex" : 1,"age" : 25,"address" : "上海","remark" : "java"}}]

查询

GET /test_index05/_search
{"query": {"bool": {"must": [{"match": {"remark": "java"}}],"should": [{"match": {"remark": {"query": "developer","boost": 2}}},{"match": {"remark": {"query": "assistant","boost": 1}}}]}}
}

结果

"hits" : [{"_index" : "test_index05","_type" : "_doc","_id" : "2","_score" : 2.611973,"_source" : {"name" : "宝塔镇河妖","sex" : 1,"age" : 25,"address" : "上海","remark" : "java developer"}},{"_index" : "test_index05","_type" : "_doc","_id" : "3","_score" : 0.9918565,"_source" : {"name" : "铁锅炖大鹅","sex" : 1,"age" : 19,"address" : "天津","remark" : "java assistant"}},{"_index" : "test_index05","_type" : "_doc","_id" : "1","_score" : 0.43250346,"_source" : {"name" : "天王盖地虎","sex" : 1,"age" : 25,"address" : "上海","remark" : "java"}}]

5.4、基于dis_max实现best fields策略进行多字段搜索

best_fields策略: 搜索的document中的某一个field,尽可能多的匹配搜索条件。
most_fields策略:与best fields相反的是,尽可能多的字段匹配到搜索条件。

dis_max语法: 直接获取搜索的多条件中的,单条件query相关度分数最高的数据,以这个数据做相关度排序。

best fields策略实现举例(是找name字段中’秀儿’匹配相关度分数或remark字段中’java developer’匹配相关度分数,哪个高,就使用哪一个相关度分数进行结果排序。)

GET /test_index06/_search
{"query": {"dis_max": {"queries": [{"match": {"remark": "java developer"}},{"match": {"name": "秀儿"}}]}}
}

结果

"hits" : [{"_index" : "test_index06","_type" : "_doc","_id" : "vkjNUIcB14FuHovqnIz1","_score" : 2.3842063,"_source" : {"name" : "秀儿","sex" : 1,"age" : 26,"book" : "Spring","remark" : "C developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "vEjNUIcB14FuHovqKIyb","_score" : 1.781607,"_source" : {"name" : "rod","sex" : 1,"age" : 25,"book" : "Spring","remark" : "java developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "vUjNUIcB14FuHovqaYzA","_score" : 0.24116206,"_source" : {"name" : "rods","sex" : 1,"age" : 26,"book" : "Spring","remark" : "python developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "v0jOUIcB14FuHovqTYw0","_score" : 0.24116206,"_source" : {"name" : "Tom","sex" : 1,"age" : 26,"book" : "Spring","remark" : "C developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "wEjOUIcB14FuHovqYYw0","_score" : 0.24116206,"_source" : {"name" : "Amy","sex" : 1,"age" : 26,"book" : "Spring","remark" : "C developer"}}]

5.5、基于tie_breaker参数优化dis_max搜索效果

我不想根据打分最高的那个字段进行排序展示,我想让其他的字段也参与进来咋办?

dis_max是将多个搜索query条件中相关度分数最高的用于结果排序,忽略其他query分数,在某些情况下,可能还需要其他query条件中的相关度介入最终的结果排序,这个时候可以使用tie_breaker参数来优化dis_max搜索。tie_breaker参数代表的含义是:将其他query搜索条件的相关度分数乘以参数值,再参与到结果排序中。如果不定义此参数,相当于参数值为0。所以其他query条件的相关度分数被忽略。

tie_breaker指定的值最大为1,除最高分字段,设置其他字段打分的策略,即其他字段得分乘指定的系数,如果不加这个tie_breaker则默认为0

GET /test_index06/_search
{"query": {"dis_max": {"queries": [{"match": {"remark": "java developer"}},{"match": {"name": "秀儿"}}],"tie_breaker": 0.5}}
}

结果

"hits" : [{"_index" : "test_index06","_type" : "_doc","_id" : "vkjNUIcB14FuHovqnIz1","_score" : 2.5047874,"_source" : {"name" : "秀儿","sex" : 1,"age" : 26,"book" : "Spring","remark" : "C developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "vEjNUIcB14FuHovqKIyb","_score" : 1.781607,"_source" : {"name" : "rod","sex" : 1,"age" : 25,"book" : "Spring","remark" : "java developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "vUjNUIcB14FuHovqaYzA","_score" : 0.24116206,"_source" : {"name" : "rods","sex" : 1,"age" : 26,"book" : "Spring","remark" : "python developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "v0jOUIcB14FuHovqTYw0","_score" : 0.24116206,"_source" : {"name" : "Tom","sex" : 1,"age" : 26,"book" : "Spring","remark" : "C developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "wEjOUIcB14FuHovqYYw0","_score" : 0.24116206,"_source" : {"name" : "Amy","sex" : 1,"age" : 26,"book" : "Spring","remark" : "C developer"}}]

5.6、使用multi_match简化dis_max+tie_breaker(不常用)

ES中相同结果的搜索也可以使用不同的语法语句来实现。

查询方式1

GET /test_index06/_search
{"query": {"dis_max": {"queries": [{"match": {"name": "Tom"}},{"match": {"remark": {"query": "java developer","boost": 2,"minimum_should_match": 2}}}],"tie_breaker": 0.5}}
}

结果

"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 3.563214,"hits" : [{"_index" : "test_index06","_type" : "_doc","_id" : "vEjNUIcB14FuHovqKIyb","_score" : 3.563214,"_source" : {"name" : "rod","sex" : 1,"age" : 25,"book" : "Spring","remark" : "java developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "v0jOUIcB14FuHovqTYw0","_score" : 1.6360589,"_source" : {"name" : "Tom","sex" : 1,"age" : 26,"book" : "Spring","remark" : "C developer"}}]

查询方式2(其中type常用的有best_fields和most_fields。^n代表权重,相当于"boost":n。)

GET /test_index06/_search
{"query": {"multi_match": {"query": "Tom java developer","fields": ["name","remark^2"],"type": "best_fields","tie_breaker": 0.5,"minimum_should_match": "50%"}}
}

结果

"hits" : [{"_index" : "test_index06","_type" : "_doc","_id" : "vEjNUIcB14FuHovqKIyb","_score" : 3.563214,"_source" : {"name" : "rod","sex" : 1,"age" : 25,"book" : "Spring","remark" : "java developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "v0jOUIcB14FuHovqTYw0","_score" : 1.877221,"_source" : {"name" : "Tom","sex" : 1,"age" : 26,"book" : "Spring","remark" : "C developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "vUjNUIcB14FuHovqaYzA","_score" : 0.48232412,"_source" : {"name" : "rods","sex" : 1,"age" : 26,"book" : "Spring","remark" : "python developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "vkjNUIcB14FuHovqnIz1","_score" : 0.48232412,"_source" : {"name" : "秀儿","sex" : 1,"age" : 26,"book" : "Spring","remark" : "C developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "wEjOUIcB14FuHovqYYw0","_score" : 0.48232412,"_source" : {"name" : "Amy","sex" : 1,"age" : 26,"book" : "Spring","remark" : "C developer"}}]

5.7、cross_fields搜索

cross fields : 一个唯一的标识,分部在多个fields中,使用这种唯一标识搜索数据就称为cross fields搜索。如:人名可以分为姓和名,地址可以分为省、市、区县、街道等。那么使用人名或地址来搜索document,就称为cross fields搜索。实现这种搜索,一般都是使用most fields搜索策略。因为这就不是一个field的问题。Cross fields搜索策略,是从多个字段中搜索条件数据。默认情况下,和most fields搜索的逻辑是一致的,计算相关度分数是和best fields策略一致的。一般来说,如果使用cross fields搜索策略,那么都会携带一个额外的参数operator。用来标记搜索条件如何在多个字段中匹配。在ES中也有cross fields搜索策略

例如(搜索条件中的java必须在name或remark字段中匹配,developer也必须在name或remark字段中匹配。)

GET /test_index06/_search
{"query": {"multi_match": {"query": "java developer","fields": ["name","remark"],"type": "cross_fields","operator": "and"}}
}

结果

"hits" : {"total" : {"value" : 1,"relation" : "eq"},"max_score" : 1.781607,"hits" : [{"_index" : "test_index06","_type" : "_doc","_id" : "vEjNUIcB14FuHovqKIyb","_score" : 1.781607,"_source" : {"name" : "rod","sex" : 1,"age" : 25,"book" : "Spring","remark" : "java developer"}}]

most field策略问题:most fields策略是尽可能匹配更多的字段,所以会导致精确搜索结果排序问题。又因为cross fields搜索,不能使用minimum_should_match来去除长尾数据。所以在使用most fields和cross fields策略搜索数据的时候,都有不同的缺陷。所以商业项目开发中,都推荐使用best fields策略实现搜索。

5.8、copy_to组合fields

场景:在电商网站,如果在搜索框中输入“手机”,点击搜索,那么是在商品的类型名称、商品的名称、商品的卖点、商品的描述等字段中,哪一个字段内进行数据的匹配?如果使用某一个字段做搜索不合适,那么使用_all做搜索是否合适?也不合适,因为_all字段中可能包含图片,价格等字段。

假设,有一个字段,其中的内容包括(但不限于):商品类型名称、商品名称、商品卖点等字段的数据内容。是否可以在这个特殊的字段上进行数据搜索匹配?(我理解的就是融合多个字段为一个,理解为该商品的摘要信息。)

以keyword字段举例,它包括了category_name、product_name、sell_point三个字段的内容。

{"category_name" : "手机","product_name" : "一加6T手机","price" : 568800,"sell_point" : "国产Android手机","tags": ["8G+128G", "256G可扩展"],"color" : "红色","keyword" : "手机 一加6T手机 国产Android手机"
}

copy_to : 就是将多个字段,复制到一个字段中,实现一个多字段组合。copy_to可以解决cross fields搜索问题,在商业项目中,也用于解决搜索条件默认字段问题。 如果需要使用copy_to语法,则需要在定义index的时候,手工指定mapping映射策略。

例如

PUT /test_index07/_mapping
{"properties": {"provice": {"type": "text","analyzer": "standard","copy_to": "address"},"city": {"type": "text","analyzer": "standard","copy_to": "address"},"street": {"type": "text","analyzer": "standard","copy_to": "address"},"address": {"type": "text","analyzer": "standard"}}
}

上述的mapping定义中,是新增了4个字段,分别是provice、city、street、address,其中provice、city、street三个字段的值,会自动复制到address字段中,实现一个字段的组合。那么在搜索地址的时候,就可以在address字段中做条件匹配,从而避免most fields策略导致的问题。在维护数据的时候,不需对address字段特殊的维护。因为address字段是一个组合字段,是由ES自动维护的。类似java代码中的推导属性。在存储的时候,未必存在,但是在逻辑上是一定存在的,因为address是由3个物理存在的属性province、city、street组成的。

5.9、近似匹配

给定一个短语,或者单词,匹配包含全部或者部分的内容。

举例(test_index06中remark字段没有go相关内容)

GET /test_index06/_search
{"query": {"match": {"remark": "developer go"}}
}

结果

"hits" : [{"_index" : "test_index06","_type" : "_doc","_id" : "vEjNUIcB14FuHovqKIyb","_score" : 0.24116206,"_source" : {"name" : "rod","sex" : 1,"age" : 25,"book" : "Spring","remark" : "java developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "vUjNUIcB14FuHovqaYzA","_score" : 0.24116206,"_source" : {"name" : "rods","sex" : 1,"age" : 26,"book" : "Spring","remark" : "python developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "vkjNUIcB14FuHovqnIz1","_score" : 0.24116206,"_source" : {"name" : "秀儿","sex" : 1,"age" : 26,"book" : "Spring","remark" : "C developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "v0jOUIcB14FuHovqTYw0","_score" : 0.24116206,"_source" : {"name" : "Tom","sex" : 1,"age" : 26,"book" : "Spring","remark" : "C developer"}},{"_index" : "test_index06","_type" : "_doc","_id" : "wEjOUIcB14FuHovqYYw0","_score" : 0.24116206,"_source" : {"name" : "Amy","sex" : 1,"age" : 26,"book" : "Spring","remark" : "C developer"}}]

举例

GET /test_index06/_search
{"query": {"match": {"remark": "developerAA"}}
}

结果

"hits" : [ ]

如果需要的结果是有特殊要求,如:java developer 必须是一个完整的短语,不可分割;或document中的field内,包含的java 和developer 单词,且两个单词之间离的越近,相关度分数越高。那么这种特殊要求的搜索就是近似搜索。 搜索包括javb内容,搜索条件在java developer数据中搜索,或包括 j 搜索提示等数据近似搜索的一部分。如何上述特殊要求的搜索,使用match搜索语法就无法实现了。

5.10、match_phrase

短语搜索。就是搜索条件不分词。代表搜索条件不可分割。

举例(只会匹配出,java developer同时出现,并且连续的内容,即java developer为一个整体出现)

GET /test_index06/_search
{"query": {"match_phrase": {"remark": "java developer"}}
}

结果

"hits" : [{"_index" : "test_index06","_type" : "_doc","_id" : "vEjNUIcB14FuHovqKIyb","_score" : 1.7816072,"_source" : {"name" : "rod","sex" : 1,"age" : 25,"book" : "Spring","remark" : "java developer"}}]

5.10.1match phrase原理 —— term position

ES是如何实现match phrase短语搜索的?其实在ES中,使用match phrase做搜索的时候,也是和match类似,首先对搜索条件进行分词-analyze。将搜索条件拆分成hello和world。既然是分词后再搜索,ES是如何实现短语搜索的?
这里涉及到了倒排索引的建立过程。在倒排索引建立的时候,ES会先对document数据进行分词,如:

查询如下句子是如何分词的

GET _analyze
{"text": "hello world, java spark","analyzer": "standard"
}

结果

{"tokens" : [{"token" : "hello","start_offset" : 0,"end_offset" : 5,"type" : "<ALPHANUM>","position" : 0},{"token" : "world","start_offset" : 6,"end_offset" : 11,"type" : "<ALPHANUM>","position" : 1},{"token" : "java","start_offset" : 13,"end_offset" : 17,"type" : "<ALPHANUM>","position" : 2},{"token" : "spark","start_offset" : 18,"end_offset" : 23,"type" : "<ALPHANUM>","position" : 3}]
}

从上述结果中,可以看到。ES在做分词的时候,除了将数据切分外,还会保留一个position。position代表的是这个词在整个数据中的下标。当ES执行match phrase搜索的时候,首先将搜索条件hello world分词为hello和world。然后在倒排索引中检索数据,如果hello和world都在某个document的某个field出现时,那么检查这两个匹配到的单词的position是否是连续的,如果是连续的,代表匹配成功,如果是不连续的,则匹配失败。

5.10.2match phrase搜索参数 – slop

场景举例:在做搜索操作的是,如果搜索参数是hello spark。而ES中存储的数据是hello world, java spark。那么使用match phrase则无法搜索到。在这个时候,可以使用match来解决这个问题。但是,当我们需要在搜索的结果中,做一个特殊的要求:hello和spark两个单词距离越近,document在结果集合中排序越靠前,这个时候再使用match则未必能得到想要的结果。

ES的搜索中,对match phrase提供了参数slop。slop代表match phrase短语搜索的时候,单词最多移动多少次,可以实现数据匹配。在所有匹配结果中,多个单词距离越近,相关度评分越高,排序越靠前。这种使用slop参数的match phrase搜索,就称为近似匹配(proximity search)

在Elasticsearch中,slop是指在查询语句中,词项之间可以允许的最大距离。它是一种模糊匹配(fuzzy matching)方式,用于解决用户输入错误或者数据存储时不准确的情况。
当我们进行一个带有slop参数的查询时,Elasticsearch将按照文档中出现的顺序检查查询语句中的每个词,并尝试找到它们之间最接近的匹配。如果两个词之间的距离小于或等于slop的值,则它们被认为是匹配的。
例子:
假设我们有以下三个文档:

{"id": 1,"title": "quick brown fox"
}
{"id": 2,"title": "quick red fox"
}
{"id": 3,"title": "slow brown dog"
}

我们希望查找包含“quick”和“fox”的文档,并且它们之间的最大距离为1。我们可以使用以下查询:

{"query": {"match_phrase": {"title": {"query": "quick fox","slop": 1}}}
}

该查询将返回文档1和2,但不会返回文档3,因为“slow”和“brown”之间的距离大于1。(关于距离你可以去看下对应的position字段,即match phrase原理 —— term position下讲解的内容)

需要注意的是,slop值越大,匹配的结果会越多,但是精度也会降低。因此,在使用slop时,需要根据实际情况进行权衡。

5.11使用match和proximity search实现召回率和精准度平衡。

召回率:召回率就是搜索结果比率,如:索引A中有100个document,搜索时返回多少个document,就是召回率(recall)。
精准度:就是搜索结果的准确率,如:搜索条件为hello java,在搜索结果中尽可能让短语匹配和hello java离的近的结果排序靠前,就是精准度(precision)。
如果在搜索的时候,只使用match phrase语法,会导致召回率低下,因为搜索结果中必须包含短语(包括proximity search)。
如果在搜索的时候,只使用match语法,会导致精准度底下,因为搜索结果排序是根据相关度分数算法计算得到。
那么如果需要在结果中兼顾召回率和精准度的时候,就需要将match和proximity search混合使用,来得到搜索结果。

索引test_index08下所有内容

"hits" : {"total" : {"value" : 4,"relation" : "eq"},"max_score" : 1.0,"hits" : [{"_index" : "test_index08","_type" : "_doc","_id" : "3","_score" : 1.0,"_source" : {"f" : "hello, java is very good, spark is also very good"}},{"_index" : "test_index08","_type" : "_doc","_id" : "4","_score" : 1.0,"_source" : {"f" : "java and spark, development language "}},{"_index" : "test_index08","_type" : "_doc","_id" : "5","_score" : 1.0,"_source" : {"f" : "Java Spark is a fast and general-purpose cluster computing system. It provides high-level APIs in Java, Scala, Python and R, and an optimized engine that supports general execution graphs."}},{"_index" : "test_index08","_type" : "_doc","_id" : "6","_score" : 1.0,"_source" : {"f" : "java spark and, development language "}}]

查询1

GET /test_index08/_search
{"query": {"match": {"f": "java spark"}}
}

结果

"hits" : {"total" : {"value" : 4,"relation" : "eq"},"max_score" : 0.28046143,"hits" : [{"_index" : "test_index08","_type" : "_doc","_id" : "4","_score" : 0.28046143,"_source" : {"f" : "java and spark, development language "}},{"_index" : "test_index08","_type" : "_doc","_id" : "6","_score" : 0.28046143,"_source" : {"f" : "java spark and, development language "}},{"_index" : "test_index08","_type" : "_doc","_id" : "3","_score" : 0.23111339,"_source" : {"f" : "hello, java is very good, spark is also very good"}},{"_index" : "test_index08","_type" : "_doc","_id" : "5","_score" : 0.16973917,"_source" : {"f" : "Java Spark is a fast and general-purpose cluster computing system. It provides high-level APIs in Java, Scala, Python and R, and an optimized engine that supports general execution graphs."}}]

查询2

GET /test_index08/_search
{"query": {"bool": {"must": [{"match": {"f": "java spark"}}],"should": [{"match_phrase": {"f": {"query": "java spark","slop": 50}}}]}}
}

结果

"hits" : [{"_index" : "test_index08","_type" : "_doc","_id" : "6","_score" : 0.56092286,"_source" : {"f" : "java spark and, development language "}},{"_index" : "test_index08","_type" : "_doc","_id" : "4","_score" : 0.4815065,"_source" : {"f" : "java and spark, development language "}},{"_index" : "test_index08","_type" : "_doc","_id" : "3","_score" : 0.32339638,"_source" : {"f" : "hello, java is very good, spark is also very good"}},{"_index" : "test_index08","_type" : "_doc","_id" : "5","_score" : 0.30782324,"_source" : {"f" : "Java Spark is a fast and general-purpose cluster computing system. It provides high-level APIs in Java, Scala, Python and R, and an optimized engine that supports general execution graphs."}}]

5.12前缀搜索 prefix search

使用前缀匹配实现搜索能力。通常针对keyword类型字段,也就是不分词的字段。

GET /test_a/_mapping
{"test_a" : {"mappings" : {"properties" : {"f" : {"type" : "text","fields" : {"keyword" : {"type" : "keyword","ignore_above" : 256}}}}}}
}

所有数据如下

"hits" : [{"_index" : "test_a","_type" : "_doc","_id" : "3","_score" : 1.0,"_source" : {"f" : "hello, java is very good, spark is also very good"}},{"_index" : "test_a","_type" : "_doc","_id" : "4","_score" : 1.0,"_source" : {"f" : "java and spark, development language "}}]

查询

GET /test_a/_search
{"query": {"prefix": {"f.keyword": {"value": "j"}}}
}

结果

    "hits" : [{"_index" : "test_a","_type" : "_doc","_id" : "4","_score" : 1.0,"_source" : {"f" : "java and spark, development language "}}]

查询

GET /test_a/_search
{"query": {"prefix": {"f.keyword": {"value": "J"}}}
}

结果

"hits" : [ ]

针对前缀搜索,是对keyword类型字段而言。而keyword类型字段数据大小写敏感。前缀搜索效率比较低。前缀搜索不会计算相关度分数。前缀越短,效率越低。如果使用前缀搜索,建议使用长前缀。因为前缀搜索需要扫描完整的索引内容,所以前缀越长,相对效率越高。

5.13通配符搜索

通配符可以在倒排索引中使用,也可以在keyword类型字段中使用。
(性能很低,也是需要扫描完整的索引)
? :表示一个任意字符
*·:表示0~n个任意字符
查询

GET /test_a/_search
{"query": {"wildcard": {"f.keyword": {"value": "?e*o*"}}}
}

结果

"hits" : [{"_index" : "test_a","_type" : "_doc","_id" : "3","_score" : 1.0,"_source" : {"f" : "hello, java is very good, spark is also very good"}}]

5.14正则搜索

在Elasticsearch中,regexp查询是一种使用正则表达式进行搜索的查询方式。它可以在指定字段上匹配满足正则表达式的文本。

ES支持正则表达式,可以在倒排索引或keyword类型字段中使用。
例如,假设我们有一个包含文档标题和内容的索引,并想要查找所有标题或内容中包含“Elastic”和“search”的文档。这时候,就可以使用regexp查询来实现:

{"query": {"regexp": {"_all": ".*Elastic.*search.*"}}
}

在上述例子中,“_all” 表示对所有字段进行搜索,".*"表示任意字符出现0次或多次。

需要注意的是,正则表达式的查询效率较低,因为它需要对每个文档的每个字段都进行逐一匹配。如果对性能要求较高,应该尽量避免使用正则表达式查询。

另外,Elasticsearch还支持设置正则表达式的参数,如ignore_case(是否忽略大小写),max_determinized_states(最大化自动机状态数),boost(权重系数),以及flags(正则表达式标志)。这些参数可以提高查询的准确性和灵活性。

再举例

GET /test_a/_search
{"query": {"regexp": {"f.keyword": "[A-z].+"}}
}

结果

"hits" : [{"_index" : "test_a","_type" : "_doc","_id" : "3","_score" : 1.0,"_source" : {"f" : "hello, java is very good, spark is also very good"}},{"_index" : "test_a","_type" : "_doc","_id" : "4","_score" : 1.0,"_source" : {"f" : "java and spark, development language "}}]

性能很低,需要扫描完整索引,应该尽量避免在大型索引中使用

5.15搜索推荐

在Elasticsearch中,match_phrase_prefix查询是一种结合了match和prefix两种查询的组合查询。它可以用于匹配以指定前缀开头的短语。

具体来说,match_phrase_prefix查询会先将查询字符串拆分成一个个词项(term),然后使用前缀匹配算法进行匹配。通常情况下,match_phrase_prefix查询适用于需要匹配长短语但又希望支持前缀匹配的场景。
搜索推荐: search as your type, 搜索提示。如:索引中有若干数据以“hello”开头,那么在输入hello的时候,推荐相关信息。(类似百度输入框)

查询

GET /test_a/_search
{"query": {"match_phrase_prefix": {"f": {"query": "java s","slop": 10,"max_expansions": 10}}}
}

结果

"hits" : [{"_index" : "test_a","_type" : "_doc","_id" : "4","_score" : 0.28650534,"_source" : {"f" : "java and spark, development language "}},{"_index" : "test_a","_type" : "_doc","_id" : "3","_score" : 0.11460209,"_source" : {"f" : "hello, java is very good, spark is also very good"}}]

其原理和match phrase类似,是先使用match匹配term数据(java),然后在指定的slop移动次数范围内,前缀匹配(s),max_expansions是用于指定prefix最多匹配多少个term(单词),超过这个数量就不再匹配了。
这种语法的限制是,只有最后一个term会执行前缀搜索。
执行性能很差,最后一个term是需要扫描所有符合slop要求的倒排索引的term。
因为效率较低,如果必须使用,则一定要使用参数max_expansions。

5.16fuzzy模糊搜索技术

Elasticsearch中的fuzzy模糊搜索技术是一种基于编辑距离(Levenshtein Distance)算法的全文检索技术。它允许在查询时匹配相似但不完全相同的单词。具体来说,当我们进行一个fuzzy query时,Elasticsearch将会在索引中查找与查询字符串最接近的项。如果查询字符串中有一个拼写错误或者一个字符丢失,fuzzy search可以帮助我们找到那些被错误拼写的项。另外,fuzzy search也能够在搜索时匹配多个单词之间的相似性。在Elasticsearch中,我们可以使用fuzziness参数来设置模糊度,该参数表示最大编辑距离,即允许的最大差异数量。默认值为2,这意味着如果两个单词的编辑距离超过2,则它们将不会被匹配。我们可以通过增加或减少该参数来调整模糊度,以便更好地满足我们的需求。

搜索的时候,可能搜索条件文本输入错误,如:hello world -> hello word。这种拼写错误还是很常见的。fuzzy技术就是用于解决错误拼写的(在英文中很有效,在中文中几乎无效。)。其中fuzziness代表value的值word可以修改多少个字母来进行拼写错误的纠正(修改字母的数量包含字母变更,增加或减少字母。)。f代表要搜索的字段名称。
查询

GET /test_a/_search
{"query": {"fuzzy": {"f": {"value": "word","fuzziness": 2}}}
}

结果

 "hits" : [{"_index" : "test_a","_type" : "_doc","_id" : "3","_score" : 0.43569255,"_source" : {"f" : "hello, java is very good, spark is also very good"}}]

  1. Zen Discovery 是 Elasticsearch 中的一种自动发现机制,它用于在分布式环境下管理节点的发现和连接。Zen Discovery 能够自动感知节点的加入和离开,并在必要时重新分配数据和重新平衡群集。
    Zen Discovery 机制包括以下几个方面:
    1.Ping 操作:每个节点会定期向其他节点发送 ping 请求,以确定其他节点是否还在运行。如果一个节点在一定时间内没有响应,那么它就被认为已经离开了群集。
    2.Unicast 发现:节点之间可以通过互相发送地址列表来进行发现。在这种方式下,节点需要知道其他节点的 IP 地址和端口号,才能够加入群集。当节点启动时,它会向配置的节点列表发送加入请求,如果请求成功,则会将该节点加入群集。
    3.Multicast 发现:在使用 Multicast 发现机制时,节点可以通过多播地址来进行发现。每个节点将自己的 IP 地址和端口号发布到特定的多播地址上,其他节点可以从该地址上接收到所有节点的信息,从而发现新的节点。这种方式下,节点可以更加灵活地管理群集,可以随时加入和离开群集。
    4.Master 选举:Zen Discovery 还包括了 Master 节点的选举机制,选举出的 Master 节点会负责协调群集中的各个节点。
    (当然,在某些情况下,可能需要手动指定主节点或禁用主节点竞选过程。可以通过在 elasticsearch.yml 配置文件中设置 node.master 参数来实现。如果将该参数设置为 false,则表示禁用该节点的主节点竞选功能;如果将该参数设置为 true,则表示该节点可以参与主节点竞选。默认情况下,所有节点都会参与主节点竞选,因此无需手动配置。) ↩︎

  2. 在 ElasticSearch 集群中,Master 节点维护的元数据包括以下信息:
    1.集群状态:保存了当前集群的状态,如运行状态、健康状态等。
    2.索引元数据:保存了所有索引的信息,例如字段映射、分片数量、副本数量、索引别名等。
    3.节点元数据:保存了所有节点的信息,例如 IP 地址、节点名称、可用空间、JVM 信息等。
    4.分片分配信息:保存了每个分片所属的节点信息、是否是主分片等。
    5.节点故障检测信息:保存了节点最近一次的心跳信息和下线时间,用于检测节点是否失效。
    这些元数据都存储在 Master 节点的内存中,并与其他节点进行同步,以确保集群中所有节点都拥有相同的元数据视图。通过 Master 节点维护这些元数据,可以实现集群管理和协调,确保数据的高可用性、一致性和完整性。 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/352956.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

服务器修改合作模式,饥荒的服务器合作模式 | 手游网游页游攻略大全

发布时间&#xff1a;2015-11-21 合作模式专家难度 第一:FPS游戏的硬件基础 1.一个能帮你准确分辨声音方向的耳机.某些人,队友不在他的视线内被HUNTER扑了,SMOKER拉了,他浑然不知还津津乐道地打他前面的僵尸(特殊僵尸出 ... 标签&#xff1a; 生存之旅 发布时间&#xff1a;201…

未转变者2.2.4怎么创建服务器,未转变者2period;2period;4墙怎么做 | 手游网游页游攻略大全...

发布时间&#xff1a;2016-08-18 里面大家见过可以自动修复的墙吗?今天小编就为大家带来了我的世界可自动修复墙的制作视频教程,非常不错的哦,想学的话下面跟我一起来看看吧. 自动修复墙制作视频教程 标签&#xff1a; 攻略 我的世界 建筑 红石 视频解说 发布时间&#xff1a;…

背包DP-入门篇

目录 01背包&#xff1a; 完全背包&#xff1a; 多重背包&#xff1a; 分组背包&#xff1a; 01背包&#xff1a; [NOIP2005 普及组] 采药 - 洛谷https://www.luogu.com.cn/problem/P1048 01背包背景 在一个小山上&#xff0c;有个n个黄金和一个容量为w的背包&#xff0c;…

独自去旅行你必须知道的事—勇气小姐独行攻略(内有拍照秘籍哦)

前言 每一次准备出游前&#xff0c;遇到的朋友总会问我“这次和谁一起出发&#xff1f;”80%的时候我的答案都是“和我自己&#xff01;”随着我一次次平安归来后分享的旅行趣事&#xff0c;朋友们的情绪也从担心、不解、疑惑转变成钦佩、向往和难以抑制的冲动。可是&#xff0…

Three.js打造H5里的“3D全景漫游”秘籍

近来风生水起的VR虚拟现实技术&#xff0c;抽空想起年初完成的“星球计划”项目&#xff0c;总结篇文章与各位分享一下制作基于Html5的3D全景漫游秘籍。 QQ物联与深圳市天文台合作&#xff0c;在手Q“发现新设备”-“公共设备”里&#xff0c;连接QQ物联摄像头为用户提供2016年…

QQ物联打造H5里的“3D全景漫游”秘籍

QQ截图20160524143715.jpg (21.15 KB, 下载次数: 15) 下载附件 2016-5-26 10:58 上传 近来风生水起的 VR 虚拟现实技术&#xff0c;抽空想起年初完成的“星球计划”项目&#xff0c;总结篇文章与各位分享一下制作基于 Html5 的 3D 全景漫游秘籍。 ————本文很长——能看完是…

html5 3d场景设计,打造H5里的“3D全景漫游”秘籍 - 腾讯ISUX

原标题:打造H5里的“3D全景漫游”秘籍 - 腾讯ISUX 近来风生水起的VR虚拟现实技术,抽空想起年初完成的“星球计划”项目,总结篇文章与各位分享一下制作基于Html5的3D全景漫游秘籍。 QQ物联与深圳市天文台合作,在手Q“发现新设备”-“公共设备”里,连接QQ物联摄像头为用户提…

星际战一直显示网络无法连接服务器,星际战甲服务器连接失败 | 手游网游页游攻略大全...

发布时间&#xff1a;2016-01-26 星际战甲可能很多玩家认为是个坑.因为有些段位的考试有点难.有点坑.所以会失败.那么来看看小编的星际战甲段位考试失败了怎么办 段位考试失败怎么重新参加吧. 当你在段位考试中失败,你需要等待24小时才能再次参加段位考试,同样 ... 标签&#x…

软件工程期末题目分析

一、软件工程概论 1.当你准备参与开发一个系统的时候&#xff0c;如果你对这个系统的问题领域不是很熟悉&#xff0c;那么最好不要采用以下哪种系统开发模型&#xff1f;&#xff08;A&#xff09; A、瀑布模型B、原型模型C、螺旋模型D、喷泉模型 瀑布模型模型要求用户需求明…

TS_React:类型化EventHandler

❝ 焦虑可分为「有用焦虑」和「无用焦虑」两种。 有用焦虑指向现在 无用焦虑指向未来&#xff0c;它的本质&#xff0c;是对现在失控的恐惧 ❞ 大家好&#xff0c;我是「柒八九」。 今天还是--「TypeScript实战系列」的文章。前面的文章中&#xff0c;我们从不同的角度介绍了&a…

OpenHarmony的线程间通信EventHandler

一、初识EventHandler ​ 在OpenHarmony的开发过程中&#xff0c;如果遇到处理下载、运算等较为耗时的操作时&#xff0c;会阻塞当前线程&#xff0c;但是实际操作中又不希望当前线程受到阻塞。比如&#xff1a;我们的app在界面上有一个下载文件的处理按钮&#xff0c;如果在按…

cocos 的EventHandler 事件派发器

cocos 的EventHandler 事件派发器 cc.Component.EventHandler 类 官方说明 “EventHandler” 类用来设置场景中的事件回调&#xff0c;该类允许用户设置回调目标节点&#xff0c;目标组件名&#xff0c;组件方法名&#xff0c;并可通过 emit 方法调用目标函数。 */export clas…

C# 的 事件 与 EventHandler

事件接受与发送是通过 委托来实现的&#xff0c;随意&#xff0c;在学习事件之前一定要知道委托。 首先我们先看下图&#xff1a;上的图不完整人&#xff0c;但大概是这个意思。 我们要创建一个事件管理。 来处理发布者发送消息和订阅者的接受消息中间转接。 然后订阅者去创建…

C# 实例解析事件委托之EventHandler

概述 事件属于委托的一个子集&#xff0c;像我们平时界面上的鼠标点击按钮后响应事件、事件的发布和订阅等都需要用到委托.通过委托可以很好的实现类之间的解耦好。事件委托EventHandler的 函数原型如下&#xff1a;delegate 表示这个个委托&#xff0c;事件委托没有返回值&…

wpf中EventHandler的使用

应用情景&#xff1a;比如点击A界面的a按钮&#xff0c;跳转到B界面了&#xff0c;点击b按钮后&#xff0c;触发了业务逻辑&#xff0c;然后需要回到A界面中执行某一个方法。不是唯一的方法&#xff0c;可以使用别的方法&#xff0c;类似观察者模式&#xff0c;有变化了&#x…

使用Transformer模型进行计算机视觉任务的端对端对象检测

Transformer模型是google团队在2017在论文attention is all you need中提出的一个用于NLP领域的模型,但是随着VIT模型与Swin Transformer模型的发布,把Transformer模型成功应用到计算机视觉任务中。 上期图文,我们使用hugging face的transformers模型进行了VIT模型的对象分…

3、线程通信EventHandler使用

作者&#xff1a;韩茹 公司&#xff1a;程序咖&#xff08;北京&#xff09;科技有限公司 鸿蒙巴士专栏作家 一、使用场景 EventHandler开发场景 EventHandler的主要功能是将InnerEvent事件或者Runnable任务投递到其他的线程进行处理&#xff0c;其使用的场景包括&#xff1a…

ChatGPT市场营销指南震撼出炉,你错过了?!

ChatGPT是一种基于AI技术的语言模型&#xff0c;它可以与用户进行对话和交互。它被广泛应用于各个领域&#xff0c;包括市场营销。作为一名市场营销人员&#xff0c;您可以使用ChatGPT来获得创意、解决问题和生成内容。 下面是190个ChatGPT提示&#xff0c;可帮助营销人员更好…

专业分析┃微电子专业介绍及发展前瞻

不知道提到微电子&#xff0c;你最先想到的是什么&#xff1f;芯片&#xff1f;卡脖子&#xff1f;摩尔定律&#xff1f; 因为近两年芯片被限制的原因&#xff0c;大家经常可以从各路媒体上看到“芯片”一词。微电子作为一个学科&#xff0c;简单的说&#xff0c;就是研究如何…

Cookie和session工作流程详解

目录 cookie机制 session会话 理解会话机制 Servlet中对Cookie和Session提供的 HttpServletrequest类中的方法&#xff1a; 模拟实现登录功能 首先实现功能分为两个界面&#xff1a; &#xff08;1&#xff09;登录页面代码&#xff08;前端代码&#xff09; (2) 编写Lo…