Elasticsearch 高级

Elasticsearch 高级

建议阅读顺序:

  1. Elasticsearch 入门
  2. Elasticsearch 搜索
  3. Elasticsearch 搜索高级
  4. Elasticsearch高级(本文)

1. nested 类型

1.1 介绍

Elasticsearch 中的 nested 类型允许你在文档内存储复杂的数据结构,比如一个用户可能有多个地址,或者一个博客文章可能有多个标签等。nested 类型可以让你索引这些复杂数据,并且允许你对嵌套的数据进行查询。

1.2 添加 nested 文档

向商品映射中添加 nested 类型的字段 attr_list

  • attr_list 表示商品属性
  • attr_list 有两个字段:color、memory
PUT /items/_mapping
{"properties":{"attr_list":{"type":"nested","properties":{"name":{ "type":"keyword" },"value":{ "type":"keyword" }}}}
}

由于添加了字段,所以需要对 items 索引进行更新,但是建议先删后加:

DELETE /items
PUT /items
{"mappings" : {"properties" : {"brand" : { "type" : "keyword" },"category" : { "type" : "keyword" },"commentCount" : { "type" : "integer", "index" : false },"id" : { "type" : "keyword" },"image" : { "type" : "keyword", "index" : false },"isAD" : { "type" : "boolean" },"name" : {"type" : "text","analyzer" : "ik_max_word","search_analyzer" : "ik_smart"},"price" : { "type" : "integer" },"sold" : { "type" : "integer" },"stock" : { "type" : "integer" },"updateTime" : { "type" : "date" },"location" : { "type" : "geo_point" },"attr_list":{"type":"nested","properties":{"name":{ "type":"keyword" },"value":{ "type":"keyword" }}}}}
}

在实体类上添加属性:

// 商品属性
@ApiModelProperty("商品规格")
private List<Spec> attr_list;@Data
public static class Spec {private String name;private String value;
}

向索引添加文档,可以添加单个文档也可以批量添加文档,添加文档时指定商品属性:

@Test
void testAddDocument2() throws Exception {// 商品idLong id = 317578L;// 根据id查询商品Item item = itemService.getById(id);// 转为ItemDocItemDoc itemDoc = BeanUtils.copyBean(item, ItemDoc.class);ItemDoc.Spec spec_1 = new ItemDoc.Spec();spec_1.setName("大小");spec_1.setValue("60*40");// 再设置一个新规格ItemDoc.Spec spec_2 = new ItemDoc.Spec();spec_2.setName("颜色");spec_2.setValue("白色");itemDoc.setAttr_list(List.of(spec_1, spec_2));// 使用esClient添加文档IndexResponse response = esClient.index(i -> i.index("items").id(id.toString()).document(itemDoc));// 打印结果String s = response.result().jsonValue();log.info("添加文档结果:{}", s);
}

查询文档:GET /items/_doc/{id}

1.3 搜索 nested

查询商品颜色是白色的商品:

GET /items/_search
{"query": {"nested": {"path": "attr_list","query": {"bool": {"must": [{ "term": { "attr_list.name": { "value": "颜色" } } },{ "term": { "attr_list.value": { "value": "白色" } } }]}}}}
}

"nested":这是一个嵌套查询,用于查询嵌套对象。它允许你在嵌套对象中执行更复杂的查询。

"path": "attr_list":指定了要查询哪个嵌套对象字段。在这个例子中,嵌套对象的字段名是attr_list

1.4 聚合 nested

先按商品属性名称聚合,再按属性值聚合:

GET /items/_search
{"size": 0,"aggs": {"attr_aggs": {"nested": { "path": "attr_list" },"aggs": {"attr_name_aggs": {"terms": { "field": "attr_list.name", "size": 10 },"aggs": {"attr_value_aggs": {"terms": { "field": "attr_list.value", "size": 10 }}}}}}}
}

1.5 Java Client

1.5.1 nested 查询

将 “查询商品颜色是白色的商品” 的 DSL 转为对应代码:

@Test
void testNested() throws Exception {SearchRequest.Builder builder = new SearchRequest.Builder();builder.index("items");builder.query(q -> q.nested(n -> n.path("attr_list").query(q1 -> q1.bool(b -> b.must(a -> a.term(t -> t.field("attr_list.name").value("颜色"))).must(a1 -> a1.term(t -> t.field("attr_list.value").value("白色")))))));SearchRequest build = builder.build();SearchResponse<ItemDoc> response = esClient.search(build, ItemDoc.class);// 解析结果List<Hit<ItemDoc>> hits = response.hits().hits();hits.forEach(hit -> {ItemDoc source = hit.source();log.info("查询结果:{}", source);});
}
1.5.2 nested 聚合

将 “先按商品属性名称聚合,再按属性值聚合” 的 DSL 转为对应代码:

@Test
void testNestedAggs() throws Exception {SearchRequest.Builder builder = new SearchRequest.Builder();builder.index("items2");builder.size(0);builder.aggregations("attr_aggs", a -> a.nested(n -> n.path("attr_list")).aggregations("attr_name_aggs", a1 -> a1.terms(t -> t.field("attr_list.name").size(10)).aggregations("attr_value_aggs", a2 -> a2.terms(t -> t.field("attr_list.value")))));SearchRequest build = builder.build();SearchResponse<ItemDoc> response = esClient.search(build, ItemDoc.class);Map<String, Aggregate> aggregations = response.aggregations();Aggregate attrAggs = aggregations.get("attr_aggs");//解析结果NestedAggregate nested = attrAggs.nested();Map<String, Aggregate> attrNameAggs = nested.aggregations();Aggregate aggregate = attrNameAggs.get("attr_name_aggs");aggregate.sterms().buckets().array().forEach(bucket -> {String key = bucket.key().stringValue();Long docCount = bucket.docCount();log.info("属性名:{},属性值数量:{}", key, docCount);Map<String, Aggregate> aggregations1 = bucket.aggregations();Aggregate attrValueAggs = aggregations1.get("attr_value_aggs");attrValueAggs.sterms().buckets().array().forEach(bucket1 -> {String key1 = bucket1.key().stringValue();Long docCount1 = bucket1.docCount();log.info("属性值:{},属性值数量:{}", key1, docCount1);});});
}

2. 同义词

2.1 设置同义词

搜索中同义词的需求:在搜索时输入一个关键字,包含关键字同义词的文档应该也可以搜索出来。

比如:输入“电脑”,会搜索出包含 “计算机” 的文档,输入 “黑马” 搜索出 “黑马程序员”、“传智播客” 的文章。

elasticsearch 的同义词有如下两种形式:

  1. 单向同义词:

    heima,黑马=>黑马程序员,黑马、传智播客
    

    箭头左侧的词都会映射成箭头右侧的词。

    输入箭头左侧的词可以搜索出箭头右侧的词。

  2. 双向同义词:

    马铃薯, 土豆, potato
    

    双向同义词可以互相映射。

    输入 “土豆” 可以搜索出 “potato”,输入 “potato” 可以搜索出 “土豆”

怎么设置同义词?

首先在同义词加到 synonyms.txt 文件中,synonyms.txt 文件在 es 的 config 目录下。

在 synonyms.txt 中加入:

中国,中华人民共和国,china
heima,黑马=>黑马程序员,黑马、传智播客
...

2.2 定义同义词分词器

在设置索引映射时自定义同义词分词器 my_synonyms_analyzer,并且用于 “title” 字段的搜索。

PUT /test_index
{"settings": {"analysis": {"filter": {"my_synonym_filter": {"type": "synonym","updateable": true,"synonyms_path": "synonyms.txt"}},"analyzer": {"my_synonyms_analyzer": {"tokenizer": "ik_smart","filter": [ "my_synonym_filter" ]}}}},"mappings": {"properties": {"title": {"type": "text","analyzer": "ik_max_word","search_analyzer": "my_synonyms_analyzer"}}}
}

参数说明:

  • my_synonym_filter 是自定义的词汇过滤器
  • my_synonyms_analyzer 是自定义的分析器,my_synonyms_analyzer 包含并引用了 my_synonym_filter
  • updateable 指示能否动态更新,必须为 true 才能动态更新同义词;
  • synonyms_path 指示同义词文件的位置;
  • my_synonyms_analyzer 分析器里用 ik_smart 的分词器,my_synonyms_analyzer 的分词流程是原始文本先经过 ik_smart 分词的结果再用 my_synonym_filter 处理;
  • mappings.properties.title.search_analyzer 指示 title 字段在搜索时使用 my_synonyms_analyzer 分析器。

2.3 测试

先向 test_index 索引中添加数据:

POST /_bulk
{"index": {"_index":"test_index", "_id": "5"}}
{"title": "china你好"}
{"index": {"_index":"test_index", "_id": "4"}}
{"title": "中国你好"}
{"index": {"_index":"test_index", "_id": "6"}}
{"title": "中华人民共和国你好"}
{"index": {"_index":"test_index", "_id": "7"}}
{"title": "China你好"}
{"index": {"_index":"test_index", "_id": "8"}}
{"title": "这是一匹黑马"}
{"index": {"_index":"test_index", "_id": "9"}}
{"title": "黑马是中国良心培训机构"}
{"index": {"_index":"test_index", "_id": "10"}}
{"title": "黑马程序员是中国良心培训机构"}
{"index": {"_index":"test_index", "_id": "11"}}
{"title": "传智播客一所IT培训机构"}

搜索关键字 “china”:

GET /test_index/_search
{"query": {"match": { "title": "china" }}
}

分析查询到的结果,会发现,查询到的结果只有包含关键字的值,很显然同义词并没有生效,此时就要开启同义词生效,执行 POST /test_index/_reload_search_analyzers

3. 自动补全

3.1 介绍

当在搜索框输入字符时提示出与该字符有关的搜索项,这个效果就是自动补全。

Elasticsearch 如何实现自动补全?

要实现上述自动补全的需求需要完成两个功能:

  1. 拼音搜索
  2. 前缀搜索

3.2 拼音分词器

3.2.1 安装拼音分词器

与 IK 分词器一样,拼音分词器也有插件,在 GitHub 上有 elasticsearch 的拼音分词插件。

地址:https://github.com/medcl/elasticsearch-analysis-pinyin

找到与 Elasticsearch 版本一致的插件下载包。

安装方式与IK分词器一样,分三步:

  1. 解压 elasticsearch-analysis-pinyin-7.17.7.zip
  2. 上传到虚拟机中 elasticsearch 的 plugin 目录
  3. 重启 elasticsearch
  4. 测试

测试

POST /_analyze
{"text": "黑马程序员","analyzer": "pinyin"
}
3.2.2 自定义分词器

默认的拼音分词器会将每个汉字单独分为拼音,而我们希望的是每个词条形成一组拼音,需要对拼音分词器做个性化定制,形成自定义分词器。

elasticsearch 中分词器(analyzer)的组成包含三部分:

  1. character filters:在 tokenizer 之前对文本进行处理。例如删除字符、替换字符
  2. tokenizer:将文本按照一定的规则切割成词条(term)。例如 keyword,就是不分词;还有 ik_smart
  3. tokenizer filter:将 tokenizer 输出的词条做进一步处理。例如大小写转换、同义词处理、拼音处理等

声明自定义分词器的语法如下:

PUT /test_index2
{"settings": {"analysis": {// 自定义分词器"analyzer": {// 分词器名称"my_analyzer": { "tokenizer": "ik_max_word", "filter": "py" }},// 自定义tokenizer filter"filter": {// 过滤器名称"py": {// 过滤器类型,这里是pinyin"type": "pinyin","keep_full_pinyin": true,"keep_joined_full_pinyin": true,"keep_original": true,"limit_first_letter_length": 16,"remove_duplicated_term": true,"none_chinese_pinyin_tokenize": false}}}},"mappings": {"properties": {"name": {"type": "text","analyzer": "my_analyzer","search_analyzer": "ik_smart"}}}
}

属性说明:

  1. type: "pinyin"

    这指定了过滤器的类型为 pinyin,即使用拼音分词器。

  2. keep_full_pinyin: false

    控制是否保留完整的拼音形式。设置为 false 表示不保留完整的拼音形式。

  3. keep_joined_full_pinyin: true

    控制是否保留连接的完整拼音形式。设置为 true 表示保留连接的完整拼音形式,例如 “你好” 可能会被转换为 “nihao”。

  4. keep_original: true

    控制是否保留原文本。设置为 true 表示保留原文本,这在某些情况下很有用,例如需要同时支持拼音和原文本的搜索。

  5. limit_first_letter_length: 16

    控制首字母的最大长度。例如,“你好” 的首字母形式为 “n h”,这个值控制了首字母的最大长度。

  6. remove_duplicated_term: true

    控制是否移除重复的词条。设置为 true 表示移除重复的词条,这有助于减少索引大小。

  7. none_chinese_pinyin_tokenize: false

    控制是否对非中文文本也进行拼音分词。设置为 false 表示不对非中文文本进行拼音分词。

测试自定义分词器:

POST /test_index2/_analyze
{"text": "黑马程序员","analyzer": "my_analyzer"
}

3.3 自动补全查询

3.3.1 completion

Elasticsearch 专门设计 completion 查询用于自动补全,completion 查询可以实现前缀搜索的效果,性能比前缀搜索更快。

completion 查询会匹配以用户输入内容开头的词条并返回,使用 completion 查询对文档中字段的类型有一些约束:

  • 参与补全查询的字段必须是 completion 类型。
  • 字段的内容一般是用来补全的多个词条形成的数组。

在 test_index2 索引中添加 suggestion 字段并且设置为 completion 类型:

PUT /test_index2/_mapping
{"properties": {"suggestion": { "type":"completion" }}
}
3.3.2 测试

更新原有文档,文档中指定了自动补全的内容:

POST /test_index2/_update/100
{"doc": { "suggestion": ["拉杆箱","托运箱"] }
}POST /test_index2/_update/101
{"doc": { "suggestion": ["拉杆箱","旅行箱","莎米特"] }
}

测试:

GET /test_index2/_search
{"suggest" : {"suggestion_suggest" : {  "completion" : { "field": "suggestion",  "size": 10,  "skip_duplicates": true  },"text" : "旅"  }}
}

参数说明:

  1. suggest:这是建议器的顶级对象,用于配置建议器。

  2. suggestion_suggest:这是建议器的名称,可以自定义。它用于标识建议器。

  3. completion

    这是指定建议器类型的部分。在这里,我们使用的是 completion 类型,它是专门为自动补全设计的建议器。

  4. field

    这是用于建议的字段名称。在这个例子中,我们使用名为 suggestion 的字段,该字段应该已经被配置为completion类型的字段。

  5. size

    这个参数控制返回的建议数量。在这个例子中,我们设置了 size 为10,意味着最多返回10个建议。

  6. skip_duplicates

    这个参数用于控制是否在返回的建议中跳过重复的条目。在这个例子中,我们设置为 true,意味着如果某个建议在多个文档中出现,只会返回一次。

  7. text:这是用户输入的文本,用于生成建议。

3.3.3 Java Client
@Test
void testSuggest() throws IOException {SearchRequest.Builder builder = new SearchRequest.Builder();builder.index("test_index2");builder.suggest(s -> s.suggesters("suggestion_suggest", ss -> ss.completion(c -> c.field("suggestion").size(10).skipDuplicates(true)).text("拉")));SearchRequest request = builder.build();SearchResponse<Index2> response = esClient.search(request, Index2.class);Map<String, List<Suggestion<Index2>>> suggest = response.suggest();List<Suggestion<Index2>> suggestion_suggest = suggest.get("suggestion_suggest");suggestion_suggest.stream().forEach(suggestion -> {suggestion.completion().options().forEach(option -> {String text = option.text();System.out.println(text);});});
}/*** 测试自动补全模型类*/
@Data
public static class Index2 {//idprivate Long id;//nameprivate String name;private List<String> suggestion;}

3.4 拼音自动补全

3.4.1 创建自动补全字段

自定义分词器:

PUT /test_index3
{"settings": {"analysis": {"analyzer": {"completion_analyzer": { "tokenizer": "keyword", "filter": "py" }},"filter": {"py": {"type": "pinyin","keep_full_pinyin": true,"keep_joined_full_pinyin": true,"keep_original": true,"limit_first_letter_length": 16,"remove_duplicated_term": true,"none_chinese_pinyin_tokenize": false}}}},"mappings": {"properties": {"id": { "type": "keyword" },"name":{"type": "text","analyzer": "ik_max_word","search_analyzer": "ik_smart"},"suggestion":{ "type": "completion", "analyzer": "completion_analyzer" }}}
}
3.4.2 更新/新增文档
POST test_index3/_doc/100
{"id":100,"name":"RIMOWA 30寸托运箱拉杆箱 SALSA AIR系列果绿色 820.70.36.4","suggestion": ["拉杆箱","托运箱"]
}POST test_index3/_doc/101
{"id":101,"name":"莎米特SUMMIT 旅行拉杆箱28英寸PC材质大容量旅行行李箱PC154 黑色","suggestion": ["拉杆箱","旅行箱","莎米特"]
}POST test_index3/_doc/102
{"id":102,"name":"拉菲斯汀(La Festin)612026 新款女士钱包 头层牛皮短款钱包 凯利黑","suggestion": ["拉菲斯汀","女包"]
}
3.4.3 测试
GET /test_index3/_search
{"suggest": {"suggestion_suggest": {"completion": {"field": "suggestion","size": 2,"skip_duplicates": true},"text": "la"}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot实现的高校实验室管理平台功能四

一、前言介绍&#xff1a; 1.1 项目摘要 随着信息技术的飞速发展&#xff0c;高校实验室的管理逐渐趋向于信息化、智能化。传统的实验室管理方式存在效率低下、资源浪费等问题&#xff0c;因此&#xff0c;利用现代技术手段对实验室进行高效管理显得尤为重要。 高校实验室作为…

leetcode_704. 二分查找_java

704. 二分查找https://leetcode.cn/problems/binary-search/ 1.题目 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 示…

python基础学习三(元组及字符串的使用)

文章目录 元组什么是元组元组的创建方式为什么要将元组设计成不可变序列元组的遍历集合集合的相关操作集合操作集合的数学操作集合生成式列表&#xff0c;字典&#xff0c;元组&#xff0c;集合总结 字符串字符串的驻留机制判断字符串的操作方法字符串的比较操作字符串的切片操…

游戏被外挂攻破?金融数据遭篡改?AI反作弊系统实战方案(代码+详细步骤)

一、背景与需求分析 随着游戏行业与金融领域的数字化进程加速,作弊行为(如游戏外挂、金融数据篡改)日益复杂化。传统基于规则的防御手段已难以应对新型攻击,而AI技术通过动态行为分析、异常检测等能力,为安全领域提供了革命性解决方案。本文以游戏反作弊系统和金融数据安…

深入理解 TypeScript 中的类型断言(Type Assertion)

类型断言是 TypeScript 中一个强大而独特的特性&#xff0c;它允许开发者告诉编译器&#xff1a;"我知道这个值的类型是什么&#xff0c;请相信我"。本文将全面探讨类型断言的概念、语法、使用场景、最佳实践以及潜在陷阱&#xff0c;帮助你在 TypeScript 开发中更有…

matplotlib标题比x,y轴字体大,明明标题字体更大?

原始代码&#xff1a; plt.xlabel(训练轮次&#xff08;Epochs&#xff09;, fontsize14, fontweightbold, fontpropertieschinese_font) # 设置中文字体、加大、加粗 plt.ylabel(R值, fontsize14, fontweightbold, fontpropertieschinese_font) # 设置中文字体、加大、加粗…

MySQL DQL,数据查询语言的用法

语法&#xff1a;select 字段名 from 表名 [where <条件>]选择符合条件的记录 group by 字段名表 :分组 having <条件> :选择符合条件的组 order by 字段名表 …

Python练习之抽奖界面

前言 一、代码整体架构分析 1、数据层 (Model) 2、控制层 (Controller) 3、视图层 (View) 二、核心功能实现详解 1、 文件导入功能 1.1、实现逻辑 1.2、代码涉及知识点讲解 1.2.1、wildcard 1.2.2、wx.FileDialog 1.2.3、dlg.ShowModal() 2、抽奖动画控制 1.1、…

Vue3 项目通过 docxtemplater 插件动态渲染 .docx 文档(带图片)预览,并导出

Vue3 项目通过 docxtemplater 插件动态渲染 .docx 文档&#xff08;带图片&#xff09;预览&#xff0c;并导出 预览安装插件示例代码项目目录结构截图实际效果截图 动态渲染 .docx 文档&#xff08;带图片&#xff09;&#xff0c;预览、导出安装插件docx 模板文件内容完整代码…

springmvc redirect 使用https后跳转到了http://域名:443问题处理

最近在处理一个很久之前的项目的时候&#xff0c;由于需要将http升级到https&#xff0c;导致springmvc项目中配置的redirect报错 线上的返回结果是http://abc.test.com:443/jrbac/mobile/wechat.html 通过nginx配置了一下解决了&#xff0c;记录一下 location /jrbac {proxy…

用空闲时间做了一个小程序-二维码生成器

一直在摸鱼中赚钱的大家好呀~ 先向各位鱼友们汇报一下情况&#xff0c;目前小程序已经有900的鱼友注册使用过。虽然每天都有新的鱼友注册&#xff0c;但是鱼友增长的还很缓慢。自从国庆前的文字转语音的工具上线到现在已经将近有1个月没有更新小程序了。但是今天终终终终终于又…

【JavaEE】springMVC返回Http响应

目录 一、返回页面二、Controller和ResponseBody与RestController区别三、返回HTML代码⽚段四、返回JSON五、HttpServletResponse设置状态码六、设置Header6.1 HttpServletResponse设置6.2 RequestMapping设置 一、返回页面 步骤如下&#xff1a; 我们先要在static目录下创建…

【新手初学】SQL注入getshell

一、引入 木马介绍&#xff1a; 木马其实就是一段程序&#xff0c;这个程序运行到目标主机上时&#xff0c;主要可以对目标进行远程控制、盗取信息等功能&#xff0c;一般不会破坏目标主机&#xff0c;当然&#xff0c;这也看黑客是否想要搞破坏。 木马类型&#xff1a; 按照功…

验证Linux多进程时间片切换的程序

​​ 一、软件需求 在同时运行多个CPU密集型进程时&#xff0c;需采集以下统计信息&#xff1a; 当前运行在逻辑CPU上的进程ID每个进程的运行进度百分比 实验程序设计要求&#xff1a; 1. 命令行参数 参数说明示例值n并发进程数量3total总运行时长&#xff08;毫秒&…

Spring笔记03-依赖注入

简述: Spring 依赖注入&#xff08;Dependency Injection&#xff0c;DI&#xff09;是 Spring 框架的核心功能之一&#xff0c;它通过将对象的依赖关系交由 Spring 容器来管理&#xff0c;实现了对象之间的解耦&#xff0c;提高了代码的可维护性和可测试性。 构造器注入示例:…

减少采样空间方法 变成后验概率

又 因为后验概率很难计算 --所以通过引入变分分布来近似 后验概率分布 同时 引入 kl散度来度量 近似的效果好不好 什么是kl散度 kl散度带变分&#xff1a; 第一个问题 &#xff1a;积分变期望 问题二&#xff1a;贝叶斯公式 第三个问题&#xff1a;为啥可以独立出来 因为相比…

【keil】单步调试

一、步骤 1、打开stc-isp软件 2.打开keil仿真设置&#xff0c;选择对应的单片机型号 3.点击将所选目标单片机设置为仿真芯片&#xff0c;点击下载&#xff0c;按一下单片机打下载按钮 4.此时已经将仿真程序下载到单片机 5.此时点击options,找到debug选择STC Montor 51 Driv…

【即插即用涨点模块-卷积】SPDConv空间深度卷积,助力小目标与低分辨有效涨点【附源码+注释】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

UE4学习笔记 FPS游戏制作26 UE中的UI

文章目录 几个概念创建一个UI蓝图添加UI获取UI的引用 切换设计器和UI蓝图将UI添加到游戏场景锚点轴点slotSizeToContent三种UI数据更新方式函数绑定属性绑定事件绑定 九宫格分割图片 几个概念 UMG&#xff1a;UE的UI编辑器 slate UI: UE的UI的编辑语言 创建一个UI蓝图 右键用…

WebGL图形编程实战【3】:矩阵操控 × 从二维到三维的跨越

上一篇文章&#xff1a;WebGL图形编程实战【2】&#xff1a;动态着色 纹理贴图技术揭秘 仓库地址&#xff1a;github…、gitee… 矩阵操控 矩阵变换 回到前面关于平移缩放、旋转的例子当中&#xff0c;我们是通过改变传递进去的xy的值来改变的。 在进行基础变换的时候&…