Elasticsearch:如何在 Elasticsearch 中正确使用同义词功能

news2024/12/26 21:14:34

同义词用于提高搜索质量并扩大匹配范围。 例如,搜索 England 的用户可能希望找到包含 British 或 UK 的文档,尽管这三个词完全不同。

Elasticsearch 中的同义词功能非常强大,如果实施得当,可以使你的搜索引擎更加健壮和强大。 在本文中,我们将通过简单的代码片段介绍在实践中实现同义词功能的要点。 特别是,我们将介绍如何更新现有索引的同义词,这是一个相对高级的话题。

在今天的展示中,我将使用最新的 Elastic Stack 8.6.0,尽管版本不对我们的展示有任何的影响。

准备

我们将使用 Docker 在本地启动一个 Elasticsearch 服务器,并使用 Kibana 来管理索引和运行命令。 如果你以前从未使用过 Elasticsearch 或想快速复习一下,这篇文章可能会对你有所帮助。 如果你在 Docker 中运行 Elasticsearch 时遇到问题,这篇文章很可能会帮助你解决问题。在今天的文章中,我们尝试使用 docker 来部署一个没有安全功能的 Elasticsearch 集群。

准备就绪后,让我们开始探索 Elasticsearch 中的同义词功能的旅程。

我们将在本文中使用的 docker-compose.yaml 文件包含以下内容,稍后我们将向其添加更多功能:

docker-compose.yml

version: "3.9"
services:
  elasticsearch:
    image: elasticsearch:8.6.0
    environment:
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms1g -Xmx1g
      - xpack.security.enabled=false
    volumes:
      - type: volume
        source: es_data
        target: /usr/share/elasticsearch/data
    ports:
      - target: 9200
        published: 9200
    networks:
      - elastic

  kibana:
    image: kibana:8.6.0
    ports:
      - target: 5601
        published: 5601
    depends_on:
      - elasticsearch
    networks:
      - elastic      

volumes:
  es_data:
    driver: local

networks:
  elastic:
    name: elastic
    driver: bridge

你可以使用以下命令之一启动 Elasticsearch 和 Kibana:

docker-compose up

或者

docker-compose up -d

如果加上 -d 选项的话,Elasticsearch 会以 daemon 的形式来运行。上面是一种最为简单的方式来启动 Elasticsearch 集群及 Kibana。由于它没有设置安全,我们无需输入任何凭证就可以直接进入到 Kibana 了。

使用带有同义词列表的标准同义词 token 过滤器

让我们首先使用带有同义词列表的标准同义词标记过滤器创建一个索引。 在 Kibana 中运行以下命令,我们将在稍后解释详细信息: 

PUT synonyms
{
  "settings": {
    "index": {
      "analysis": {
        "analyzer": {
          "index_analyzer": {
            "tokenizer": "standard",
            "filter": [
              "lowercase",
              "synonym_filter"
            ]
          }
        },
        "filter": {
          "synonym_filter": {
            "type": "synonym",
            "synonyms": [
              "elk => Elastic Stack",
              "elkb => Elastic Stack"
            ]
          }
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "index_analyzer"
      }
    }
  }
}

这里的要点

  1. 请注意设置键的嵌套级别。 settings => index => analysis => analyzer/filter 都是内置关键字。 但是,index_analyzer 和 synonym_filter 分别是自定义分析器和过滤器的自定义名称。
  2. 我们需要创建一个 type 为 synonym 的自定义过滤器。 synonym 选项明确提供了同义词列表。 这通常应该只用于测试,因为更新同义词列表不方便,我们稍后会看到。
  3. 本文中使用了 Solr 同义词。 对于此示例,使用了显式映射,这意味着 => 左侧的标记将替换为右侧的标记。 稍后我们将使用等同的同义词,这意味着提供的 token 被等同对待。
  4. synonym_filter 添加到名为 index_analyzer 的新自定义分析器的过滤器列表中。 通常过滤器的顺序很重要。 然而,对于同义词过滤器来说,它有点特殊,可能会让我们中的许多人感到惊讶。 在此示例中,即使 synonym_filter 过滤器放在小写过滤器之后,此过滤器返回的标记也会传递给小写过滤器,因此也会变成小写。 因此,你不需要在同义词列表或同义词文件中提供小写 token。
  5. 最后,在文档的映射中,为名称字段指定了自定义分析器。

我们知道在早期的 Elastic 产品中 elk 就是 Elastic Stack 的代名词。之后随着 Beats 的加入,很多开发者也把 elkb 当做 Elastic Stack 的代名词。要测试在索引中创建的分析器,我们可以调用 _analyze 端点:

GET /synonyms/_analyze
{
  "analyzer": "index_analyzer",
  "text": "elk is powerful"
}

上面命令的输出为:

{
  "tokens": [
    {
      "token": "elastic",
      "start_offset": 0,
      "end_offset": 3,
      "type": "SYNONYM",
      "position": 0
    },
    {
      "token": "is",
      "start_offset": 4,
      "end_offset": 6,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "stack",
      "start_offset": 4,
      "end_offset": 6,
      "type": "SYNONYM",
      "position": 1
    },
    {
      "token": "powerful",
      "start_offset": 7,
      "end_offset": 15,
      "type": "<ALPHANUM>",
      "position": 2
    }
  ]
}

从上面的输出中,我们可以看到 type 为 SNONYM 的 token 为 elastic 及 stack。让我们向索引中添加一些文档并测试它在搜索中是否正常工作:

PUT /synonyms/_doc/1
{
  "name": "elk is very powerful"
}

PUT /synonyms/_doc/2
{
  "name": "elkb is useful"
}

PUT /synonyms/_doc/3
{
  "name": "Elastic Stack is so widely used"
}

我们可以使用 match 关键字进行简单的搜索:

GET /synonyms/_search?filter_path=**.hits
{
  "query": {
    "match": {
      "name": "elk"
    }
  }
}

如果没有问题,所有三个文件都应该被搜索到:

{
  "hits": {
    "hits": [
      {
        "_index": "synonyms",
        "_id": "2",
        "_score": 0.31931418,
        "_source": {
          "name": "elkb is useful"
        }
      },
      {
        "_index": "synonyms",
        "_id": "1",
        "_score": 0.29086044,
        "_source": {
          "name": "elk is very powerful"
        }
      },
      {
        "_index": "synonyms",
        "_id": "3",
        "_score": 0.24686477,
        "_source": {
          "name": "Elastic Stack is so widely used"
        }
      }
    ]
  }
}

索引时间 vs 搜索时间进行同义词操作

如你所见,在上面的示例中,只创建了一个分析器,它用于索引和搜索。

不鼓励在索引(indexing)步骤中对所有文档应用同义词,因为它有一些主要缺点:

  • 如果不重新索引所有内容,就无法更新同义词列表,这在实践中是非常低效的。
  • 搜索分数会受到影响,因为同义词 token 也会被计算在内。
  • 索引过程变得更加耗时并且索引将变得更大。 对于小数据集来说可以忽略不计,但对于大数据集来说非常重要。

因此,最好在搜索步骤中只应用同义词,这样可以克服所有三个缺点。 为此,我们需要创建一个用于搜索的新分析器。

使用 search_analyzer 并应用搜索时间同义词

在 Kibana 中运行以下命令以创建具有搜索时同义词的新索引:

PUT synonym_graph
{
  "settings": {
    "index": {
      "analysis": {
        "analyzer": {
          "index_analyzer": {
            "tokenizer": "standard",
            "filter": [
              "lowercase"
            ]
          },
          "search_analyzer": {
            "tokenizer": "standard",
            "filter": [
              "lowercase",
              "synonym_filter"
            ]
          }
        },
        "filter": {
          "synonym_filter": {
            "type": "synonym_graph",
            "synonyms": [
              "elk => Elastic Stack",
              "elkb => Elastic Stack"
            ]
          }
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "index_analyzer",
        "search_analyzer": "search_analyzer"
      }
    }
  }
}

关键点

  • 该类型现在更改为 synonym_graph,这是一个更复杂的同义词过滤器,旨在仅用作搜索分析器的一部分。 它可以更恰当地处理多词同义词,推荐用于搜索时分析。 但是,你可以继续使用原来的 synonym 类型,它在这篇文章中的表现是一样的。
  • 同义词过滤器从索引时间分析器中删除并添加到搜索时间分析器中。
  • search_analyzer 是为 name 字段明确指定的。 如果未指定,则相同的分析器 (index_analyzer) 将用于索引和搜索。

分析器应该返回与以前相同的 token。 然而,当你用这些命令为三个文档建立索引并再次执行相同的搜索后,结果会有所不同:

PUT /synonym_graph/_doc/1
{
  "name": "elk is very powerful"
}

PUT /synonym_graph/_doc/2
{
  "name": "elkb is useful"
}

PUT /synonym_graph/_doc/3
{
  "name": "Elastic Stack is so widely used"
}

我们使用如下的命令来进行搜索:

GET /synonym_graph/_search?filter_path=**.hits
{
  "query": {
    "match": {
      "name": "elk"
    }
  }
}

这一次,只有如下的结果返回。甚至 “elk is very powerful” 这个文档也没有被返回:

{
  "hits": {
    "hits": [
      {
        "_index": "synonym_graph",
        "_id": "3",
        "_score": 2.3589978,
        "_source": {
          "name": "Elastic Stack is so widely used"
        }
      }
    ]
  }
}

原因是同义词过滤器仅在搜索时应用。 搜索查询 elk 被替换为同义词标记 “Elastic Stack”。 然而,索引中的文档没有被同义词过滤器(synonym_filter)过滤,因此 “elk” 只是被标记为 elk 而没有被 Elastic Stack 替换。 类似于 elkb。 结果,只能匹配 “Elastic Stack is so widely used”。

为了使其像前面的示例一样正常工作,我们需要将同义词规则从显式映射更改为等效同义词。 让我们按如下方式更新同义词过滤器:

......
  "filter": {
    "synonym_filter": {
      "type": "synonym_graph",
        "synonyms": [
           "elk, elkb, Elastic Stack"
        ]
    }
  }
......

要更改现有索引的同义词,我们可以重新创建索引并重新索引所有文档,这是愚蠢且低效的。

更好的方法是更新索引的设置。 但是,我们需要在更新设置之前关闭索引,然后重新打开它才能访问它:

POST /synonym_graph/_close


PUT /synonym_graph/_settings
{
  "settings": {
    "index.analysis.filter.synonym_filter.synonyms": [
      "elk, elkb, Elastic Stack"
    ]
  }
}

POST /synonym_graph/_open

请注意更新索引设置的特殊语法。

运行上述命令后,我们可以通过如下命令的返回值来进行验证:

GET synonym_graph

上面的命令返回:

{
  "synonym_graph": {
    "aliases": {},
    "mappings": {
      "properties": {
        "name": {
          "type": "text",
          "analyzer": "index_analyzer",
          "search_analyzer": "search_analyzer"
        }
      }
    },
    "settings": {
      "index": {
        "routing": {
          "allocation": {
            "include": {
              "_tier_preference": "data_content"
            }
          }
        },
        "number_of_shards": "1",
        "provided_name": "synonym_graph",
        "creation_date": "1673501061514",
        "analysis": {
          "filter": {
            "synonym_filter": {
              "type": "synonym_graph",
              "synonyms": [
                "elk, elkb, Elastic Stack"
              ]
            }
          },
          "analyzer": {
            "index_analyzer": {
              "filter": [
                "lowercase"
              ],
              "tokenizer": "standard"
            },
            "search_analyzer": {
              "filter": [
                "lowercase",
                "synonym_filter"
              ],
              "tokenizer": "standard"
            }
          }
        },
        "number_of_replicas": "1",
        "uuid": "UCIWtpQMTsCc1TwnvsywHA",
        "version": {
          "created": "8060099"
        }
      }
    }
  }
}

让我们使用 _analyzer 端点测试 search_analyzer 并查看生成的 token:

GET /synonym_graph/_analyze
{
  "analyzer": "search_analyzer",
  "text": "elk"
}

上述命令返回:

它表明 elk 搜索查询被三个同义词的 token 替换和扩展(由 expand 选项控制)。 它还证明,如果在索引时应用等效同义词,则结果索引的大小可以显着增加。

然后当我们再次执行相同的搜索时:

GET /synonym_graph/_search?filter_path=**.hits
{
  "query": {
    "match": {
      "name": "elk"
    }
  }
}

这次搜索的结果是:

{
  "hits": {
    "hits": [
      {
        "_index": "synonym_graph",
        "_id": "3",
        "_score": 1.6949677,
        "_source": {
          "name": "Elastic Stack is so widely used"
        }
      },
      {
        "_index": "synonym_graph",
        "_id": "2",
        "_score": 1.1220688,
        "_source": {
          "name": "elkb is useful"
        }
      },
      {
        "_index": "synonym_graph",
        "_id": "1",
        "_score": 1.0126972,
        "_source": {
          "name": "elk is very powerful"
        }
      }
    ]
  }
}

我们可以看到三个文档都被搜索出来了。

使用同义词文件

上面我们一直在创建索引时直接指定同义词列表。 但是,当你有大量同义词时,将它们全部添加到索引中会很麻烦。 更好的方法是将它们存储在一个文件中,然后动态地将它们加载到索引中。 使用同义词文件有很多好处,其中包括:

  • 方便维护大量的同义词。
  • 可以被不同的索引使用。
  • 可以在不关闭索引的情况下动态重新加载。

首先,我们需要先将同义词放入一个文件中。 每行都是一个同义词规则,与上面演示的相同。 更多细节可以在官方文档中找到。

我们将创建的同义词文件称为 synonyms.txt,但可以任意命名。 它具有以下内容:

$ pwd
/Users/liuxg/data/docker8
$ ls
docker-compose.yml synonyms.txt
$ cat synonyms.txt 
# This is a comment! The file is named synonyms.txt.
elk,elkb,Elastic Stack

然后我们需要将同义词文件绑定到 Docker 容器中。 更新 docker-compose.yaml 如下:

docker-compose.yml

version: "3.9"
services:
  elasticsearch:
    image: elasticsearch:8.6.0
    environment:
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms1g -Xmx1g
      - xpack.security.enabled=false
    volumes:
      - type: volume
        source: es_data
        target: /usr/share/elasticsearch/data
      - type: bind
        source: ./synonyms.txt
        target: /usr/share/elasticsearch/config/synonyms.txt      
    ports:
      - target: 9200
        published: 9200
    networks:
      - elastic

  kibana:
    image: kibana:8.6.0
    ports:
      - target: 5601
        published: 5601
    depends_on:
      - elasticsearch
    networks:
      - elastic      

volumes:
  es_data:
    driver: local

networks:
  elastic:
    name: elastic
    driver: bridge

我们可以使用 CTRL+C 来终止之前运行的 docker,然后再次使用如下命令来启动:

docker-compose up

请注意,同义词文件已加载到容器中的 config 文件夹中。你可以进入容器并使用以下两个命令之一检查它:

# User docker
docker exec -it elasticsearch-1  bash

# User docker-compose
docker-compose exec elasticsearch bash

现在我们需要停止并重新启动服务以使更改生效。 请注意,仅重新启动服务将不起作用。

docker-compose stop elasticsearch
docker-compose up -d elasticsearch
$ docker ps
CONTAINER ID   IMAGE                 COMMAND                  CREATED          STATUS          PORTS                              NAMES
3ae4b728dd44   kibana:8.6.0          "/bin/tini -- /usr/l…"   23 seconds ago   Up 21 seconds   0.0.0.0:5601->5601/tcp             docker8-kibana-1
878c82384761   elasticsearch:8.6.0   "/bin/tini -- /usr/l…"   23 seconds ago   Up 22 seconds   0.0.0.0:9200->9200/tcp, 9300/tcp   docker8-elasticsearch-1
$ docker exec -it docker8-elasticsearch-1 bash
elasticsearch@878c82384761:~$ pwd
/usr/share/elasticsearch
elasticsearch@878c82384761:~$ ls
LICENSE.txt  NOTICE.txt  README.asciidoc  bin  config  data  jdk  lib  logs  modules  plugins
elasticsearch@878c82384761:~$ cd config/
elasticsearch@878c82384761:~/config$ ls
elasticsearch-plugins.example.yml  jvm.options             log4j2.properties  synonyms.txt
elasticsearch.keystore             jvm.options.d           role_mapping.yml   users
elasticsearch.yml                  log4j2.file.properties  roles.yml          users_roles

从上面的输出中,我们可以看到 synonyms.txt 已经被成功地加载到容器里了。

然后我们可以使用同义词文件创建一个新索引:

PUT /synonym_graph_file
{
  "settings": {
    "index": {
      "analysis": {
        "analyzer": {
          "index_analyzer": {
            "tokenizer": "standard",
            "filter": [
              "lowercase"
            ]
          },
          "search_analyzer": {
            "tokenizer": "standard",
            "filter": [
              "lowercase",
              "synonym_filter"
            ]
          }
        },
        "filter": {
          "synonym_filter": {
            "type": "synonym_graph",
            "synonyms_path": "synonyms.txt",
            "updateable": true
          }
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "index_analyzer",
        "search_analyzer": "search_analyzer"
      }
    }
  }
}

关键点

  • 对于 synonyms_path,它是同义词文件相对于 Elasticsearch 服务器中 config 文件夹的路径。
  • 添加了一个新的 updateable 字段,它指定相应的过滤器是否可更新。 我们很快就会看到如何在不关闭和打开索引的情况下重新加载搜索分析器。

这个新索引 synonym_graph_file 的行为应该与前一个 synonym_graph 的行为相同。

现在让我们在同义词文件中添加更多的同义词,其内容如下:

$ pwd
/Users/liuxg/data/docker8
$ ls
docker-compose.yml synonyms.txt
$ cat synonyms.txt 
# This is a comment! The file is named synonyms.txt.
elk,elkb,Elastic Stack
JS => JavaScript
TS => TypeScript
Py => Python

添加同义词后,我们可以关闭并打开索引使其生效。 然而,由于我们将同义词过滤器标记为可更新,我们可以重新加载搜索分析器以使更改立即生效,而无需关闭索引,因此无需停机。

要重新加载索引的搜索分析器,我们需要调用 _reload_search_analyzers 端点:

POST /synonym_graph_file/_reload_search_analyzers

上面的命令输出为:

{
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "reload_details": [
    {
      "index": "synonym_graph_file",
      "reloaded_analyzers": [
        "search_analyzer"
      ],
      "reloaded_node_ids": [
        "tZLy82KRTaiCdpsbkEYnuA"
      ]
    }
  ]
}

现在,当我们分析 JS 字符串时,我们将看到返回的 javascript token。

GET /synonym_graph_file/_analyze
{
  "analyzer": "search_analyzer",
  "text": "JS"
}

上面的命令返回:

{
  "tokens": [
    {
      "token": "javascript",
      "start_offset": 0,
      "end_offset": 2,
      "type": "SYNONYM",
      "position": 0
    }
  ]
}

这里应该注意两件重要的事情:

  • 如果同义词过滤器的 updateable 设置为true,那么对应的分析器只能作为 search_analyzer 使用,不能用于索引,即使类型是同义词。
  • updateable 选项只能在同义词文件与 synonyms_path 选项一起使用时使用,而不是在同义词直接通过 synonyms 选项提供时使用。

恭喜你到达这里! 我们已经涵盖了在 Elasticsearch 中使用同义词功能的所有要点。

我们已经分别介绍了如何在索引时间和搜索时间分析步骤中使用同义词。 此外,还介绍了如何直接提供同义词列表,以及如何通过文件提供。 最后但同样重要的是,介绍了关于如何更新现有索引的同义词列表的不同方法。 建议重新加载索引的搜索分析器,因为它不会给服务带来停机时间。

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

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

相关文章

详解结构体内存对齐

目录 前言 一、结构体内存对齐规则 二、 offsetof 宏 三、结构体内存对齐的原因 四、 修改默认对齐数 前言 引入问题&#xff1a; #include <stdio.h>struct S {char c1;int i;char c2; };int main() {printf("%zd\n", sizeof(struct S));return 0; } 程…

干货 | 人脸识别技术的风险及应对方案

以下内容整理自清华大学《数智安全与标准化》课程大作业期末报告同学的汇报内容。第一部分&#xff1a;人脸识别技术概述人脸识别的发展阶段&#xff0c;主要分为三个阶段&#xff1a;起步阶段&#xff08;1950s-1980s&#xff09;&#xff0c;这一阶段的人脸识别只是作为一般性…

房产管理系统---系统安全性需求分析

数图互通高校房产管理系统是基于公司自主研发的FMCenterV5.0平台&#xff0c;是针对中国高校房产的管理特点和管理要求&#xff0c;研发的一套标准产品&#xff1b;通过在中国100多所高校的成功实施和迭代&#xff0c;形成了一套成熟、完善、全生命周期的房屋资源管理解决方案。…

Linux学习笔记——HBase集群安装部署

5.11、大数据NoSQL数据库HBase集群部署 5.11.1、简介 HBase是一种分布式、可扩展、支持海量数据存储的NoSQL数据库。 和Redis一样&#xff0c;HBase是一款KeyValue型存储的数据库。 不过和Redis设计方向不同&#xff1a; Redis设计为少量数据&#xff0c;超快检索HBase设计…

【部署】Docker容器

Docker 使用 Google 公司推出的 Go 语言进行开发实现&#xff0c;基于 Linux 内核的 cgroup、namespace 以及 OverlayFS 类的 Union FS 等技术&#xff0c;对进程进行封装隔离&#xff0c;属于操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程&#xff0…

算法刷题打卡第63天:对称二叉树

对称二叉树 难度&#xff1a;简单 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false…

BOM浏览器对象模型

文章目录一、BOM概述1、什么是BOM2、BOM的构成二、window 对象的常见事件1、窗口加载事件&#xff08;1&#xff09;window.onload&#xff08;3&#xff09;DOMContentLoaded2、调整窗口大小事件三、定时器1、两种定时器2、setTimeout()定时器3、停止 setTimeout() 定时器4、s…

如何使用CMD修复硬盘命令来解决硬盘问题?

随着计算机的越来越普及&#xff0c;现在在我们的日常生活中都会使用到计算机电脑。硬盘作为计算机电脑的主要存储设备&#xff0c;里面存储着我们平时使用的软件文件、文档资料、照片等重要的数据文件。一旦硬盘损坏会给我们带来许多不必要的麻烦&#xff0c;那硬盘损坏有哪些…

图解卡尔曼滤波(Kalman Filter)

背景关于滤波首先援引来自知乎大神的解释。“一位专业课的教授给我们上课的时候&#xff0c;曾谈到&#xff1a;filtering is weighting&#xff08;滤波即加权&#xff09;。滤波的作用就是给不同的信号分量不同的权重。最简单的loss pass filter&#xff0c; 就是直接把低频的…

【Linux操作系统】1. Linux操作系统简介、安装

前言 本系列是Linux操作系统的一些知识以及实践内容&#xff0c;Linux操作系统作为开发最常使用的操作系统&#xff0c;是必备的一门求职、提升技术。本文先介绍Linux操作系统&#xff0c;并安装一个Linux操作系统。 Linux操作系统简介 Linux&#xff0c;全称GNU/Linux&#…

Javadoc

Javadoc 在学习JavaSE时&#xff0c;我们知道Java支持三种注释方式&#xff1a; 单行注释多行注释文档注释 Javadoc是文档注释&#xff0c;用来对类或方法进行标准的注释&#xff0c;在开发中写好JavaDoc非常重要。 在调用方法时&#xff0c;你可能会看到这样的情景 这种注…

Unity - 搬砖日志 - 如何设置AssetDatabase.Create(“xxx.asset“, mesh) 的Read/Write=false

最近很忙&#xff0c;想写的 BLOG 都遗漏编写了 踩坑的时间比较多&#xff0c;充电的时间少了很多 为了减少以后自己填坑时间&#xff0c;随便简单的记录一下 搬砖日志 环境 unity : 2020.3.37f1 pipeline : brp 问题 因为之前搜索、购买、使用了各式各样的 LOD 插件、工具…

机器学习100天(三十一):031 K近邻回归算法

机器学习100天,今天讲的是:K 近邻回归算法! 《机器学习100天》完整目录:目录 一、理论介绍 我们之前讲了 K 近邻分类算法,用来处理分类问题。其实 K 近邻也可以用来处理回归问题。 如左图所示,K 近邻分类算法的思路是选取与测试样本距离最近的前 k 个训练样本。然后对…

回收租赁商城系统功能拆解07讲-订单列表

回收租赁系统适用于物品回收、物品租赁、二手买卖交易等三大场景。 可以快速帮助企业搭建类似闲鱼回收/爱回收/爱租机/人人租等回收租赁商城。 回收租赁系统支持智能评估回收价格&#xff0c;后台调整最终回收价&#xff0c;用户同意回收后系统即刻放款&#xff0c;用户微信零…

寒假题练——day(3)

题目1&#xff1a; 给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。 进阶&#xff1a;尝试设计时间复杂度为 O(n)、空间复杂度为…

58、正则表达式

目录 一、快速入门 二、正则表达式基本语法 1、基本介绍&#xff1a; 2、正则表达式底层实现 3、元字符&#xff08;Metacharacter&#xff09;- 转义号\\ &#xff08;1&#xff09;限定符 &#xff08;2&#xff09;选择匹配符 &#xff08;5&#xff09;字符匹配符…

FX5U DRVMUL指令多个轴的表格运行

1.简述该指令可以用GX Works3预先在表格数据中设定的控制方式的动作&#xff0c;执行多个轴的表格。 2.指令解释同时执行多个轴的表格。指令执行开始后&#xff0c;各轴独立进行动作&#xff0c;也可连续运行。但是&#xff0c;只可在同一模块内同时执行2.1 操作数n1在(n1)中指…

.NETCore 多线程学习笔记(多线程、线程结束顺序掌控、线程相对平均分配)

参考资料&#xff1a;多线程MutiThread最佳实践专题-1-1_哔哩哔哩_bilibili 跟着视频学习的&#xff0c;下面是自己的注释笔记和实验结果 写了个窗体来学习线程的 多线程、线程掌控、线程分配 下面会用到这个方法 /// <summary> /// 仅仅只是一个耗时方法 …

STM32RTC外设详解

目录一.RTC 实时时钟简介1.RTC时钟来源2.RTC主要特性二.RTC 外设功能框图1.RTC功能框图剖析2.使能对后备寄存器和RTC的访问3.复位过程4.读RTC寄存器5.配置RTC寄存器三.实现一个简易时钟1.实验目的2.实验原理3.实验源码4.效果演示一.RTC 实时时钟简介 实时时钟是一个独立的定时…

链表题目总结 -- 双指针技巧

文章目录一. 合并两个有序链表1. 思路简述2. 代码3. 总结二. 分隔链表1. 思路简述2. 代码3. 总结三. 合并K个升序链表1. 思路简述2. 代码3. 总结四. 单链表的倒数第 k 个节点1. 思路简述2. 代码3. 总结五. 链表的中间结点1. 思路简述2. 代码3. 总结六. 环形链表&#xff08;链表…