使用阿里云试用Elasticsearch学习:1.4 基础入门——映射和分析

当摆弄索引里面的数据时,我们发现一些奇怪的事情。一些事情看起来被打乱了:在我们的索引中有12条推文,其中只有一条包含日期 2014-09-15 ,但是看一看下面查询命中的 总数 (total):

GET /_search?q=2014              # 12 results
GET /_search?q=2014-09-15        # 12 results !
GET /_search?q=date:2014-09-15   # 1  result
GET /_search?q=date:2014         # 0  results !

为什么在 _all 字段查询日期返回所有推文,而在 date 字段只查询年份却没有返回结果?为什么我们在 _all 字段和 date 字段的查询结果有差别?

推测起来,这是因为数据在 _all 字段与 date 字段的索引方式不同。所以,通过请求 gb 索引的映射(或模式定义),让我们看一看Elasticsearch 是如何解释我们文档结构的:

GET /gb/_mapping

这将得到如下结果:

{"gb": {"mappings": {"tweet": {"properties": {"date": {"type": "date","format": "strict_date_optional_time||epoch_millis"},"name": {"type": "string"},"tweet": {"type": "string"},"user_id": {"type": "long"}}}}}
}

基于对字段类型的猜测, Elasticsearch 动态为我们产生了一个映射。这个响应告诉我们 date 字段被认为是 date 类型的。由于 _all 是默认字段,所以没有提及它。但是我们知道 _all 字段是 string 类型的。

所以 date 字段和 string 字段索引方式不同,因此搜索结果也不一样。这完全不令人吃惊。你可能会认为核心数据类型 stringsnumbersBooleansdates 的索引方式有稍许不同。没错,他们确实稍有不同。

但是,到目前为止,最大的差异在于代表 精确值 (它包括 string 字段)的字段和代表 全文 的字段。这个区别非常重要——它将搜索引擎和所有其他数据库区别开来。

精确值 VS 全文

Elasticsearch 中的数据可以概括的分为两类:精确值和全文

精确值 如它们听起来那样精确。例如日期或者用户 ID,但字符串也可以表示精确值,例如用户名或邮箱地址。对于精确值来讲,Foofoo 是不同的,20142014-09-15 也是不同的。

另一方面,全文 是指文本数据(通常以人类容易识别的语言书写),例如一个推文的内容或一封邮件的内容。

全文通常是指非结构化的数据,但这里有一个误解:自然语言是高度结构化的。问题在于自然语言的规则是复杂的,导致计算机难以正确解析。例如,考虑这条语句:
May is fun but June bores me.
它指的是月份还是人?

精确值很容易查询。结果是二进制的:要么匹配查询,要么不匹配。这种查询很容易用 SQL 表示:

WHERE name    = "John Smith"AND user_id = 2AND date    > "2014-09-15"

查询全文数据要微妙的多。我们问的不只是“这个文档匹配查询吗”,而是“该文档匹配查询的程度有多大?”换句话说,该文档与给定查询的相关性如何?

我们很少对全文类型的域做精确匹配。相反,我们希望在文本类型的域中搜索。不仅如此,我们还希望搜索能够理解我们的 意图

  • 搜索 UK ,会返回包含 United Kindom 的文档。
  • 搜索 jump ,会匹配 jumped , jumps , jumping ,甚至是 leap 。
  • 搜索 johnny walker 会匹配 Johnnie Walker , johnnie depp 应该匹配 Johnny Depp 。
  • fox news hunting 应该返回福克斯新闻( Foxs News )中关于狩猎的故事,同时, fox hunting news 应该返回关于猎狐的故事。

为了促进这类在全文域中的查询,Elasticsearch 首先 分析 文档,之后根据结果创建 倒排索引 。在接下来的两节,我们会讨论倒排索引和分析过程。

倒排索引

Elasticsearch 使用一种称为 倒排索引 的结构,它适用于快速的全文搜索。一个倒排索引由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的文档列表。

例如,假设我们有两个文档,每个文档的 content 域包含如下内容:

  1. The quick brown fox jumped over the lazy dog
  2. Quick brown foxes leap over lazy dogs in summer

为了创建倒排索引,我们首先将每个文档的 content 域拆分成单独的 词(我们称它为 词条tokens ),创建一个包含所有不重复词条的排序列表,然后列出每个词条出现在哪个文档。结果如下所示:

Term      Doc_1  Doc_2
-------------------------
Quick   |       |  X
The     |   X   |
brown   |   X   |  X
dog     |   X   |
dogs    |       |  X
fox     |   X   |
foxes   |       |  X
in      |       |  X
jumped  |   X   |
lazy    |   X   |  X
leap    |       |  X
over    |   X   |  X
quick   |   X   |
summer  |       |  X
the     |   X   |
------------------------

现在,如果我们想搜索 quick brown ,我们只需要查找包含每个词条的文档:

Term      Doc_1  Doc_2
-------------------------
brown   |   X   |  X
quick   |   X   |
------------------------
Total   |   2   |  1

两个文档都匹配,但是第一个文档比第二个匹配度更高。如果我们使用仅计算匹配词条数量的简单 相似性算法 ,那么,我们可以说,对于我们查询的相关性来讲,第一个文档比第二个文档更佳。
但是,我们目前的倒排索引有一些问题:

  • Quickquick 以独立的词条出现,然而用户可能认为它们是相同的词。
  • foxfoxes 非常相似, 就像 dogdogs ;他们有相同的词根。
  • jumpedleap, 尽管没有相同的词根,但他们的意思很相近。他们是同义词。

使用前面的索引搜索 +Quick +fox 不会得到任何匹配文档。(记住,+ 前缀表明这个词必须存在。)只有同时出现 Quick 和 fox 的文档才满足这个查询条件,但是第一个文档包含 quick fox ,第二个文档包含 Quick foxes

我们的用户可以合理的期望两个文档与查询匹配。我们可以做的更好。

如果我们将词条规范为标准模式,那么我们可以找到与用户搜索的词条不完全一致,但具有足够相关性的文档。例如:

  • Quick 可以小写化为 quick
  • foxes 可以 词干提取 --变为词根的格式-- 为 fox 。类似的, dogs 可以为提取为 dog
  • jumpedleap 是同义词,可以索引为相同的单词 jump
现在索引看上去像这样:Term      Doc_1  Doc_2
-------------------------
brown   |   X   |  X
dog     |   X   |  X
fox     |   X   |  X
in      |       |  X
jump    |   X   |  X
lazy    |   X   |  X
over    |   X   |  X
quick   |   X   |  X
summer  |       |  X
the     |   X   |  X
------------------------

这还远远不够。我们搜索 +Quick +fox 仍然 会失败,因为在我们的索引中,已经没有 Quick 了。但是,如果我们对搜索的字符串使用与 content 域相同的标准化规则,会变成查询 +quick +fox ,这样两个文档都会匹配!

这非常重要。你只能搜索在索引中出现的词条,所以索引文本和查询字符串必须标准化为相同的格式。

分词和标准化的过程称为 分析 , 我们会在下个章节讨论。

分析与分析器

分析 包含下面的过程:

  • 首先,将一块文本分成适合于倒排索引的独立的 词条 ,
  • 之后,将这些词条统一化为标准格式以提高它们的“可搜索性”,或者 recall

分析器执行上面的工作。 分析器 实际上是将三个功能封装到了一个包里:
字符过滤器

  • 首先,字符串按顺序通过每个 字符过滤器 。他们的任务是在分词前整理字符串。一个字符过滤器可以用来去掉HTML,或者将 & 转化成 and
    分词器
  • 其次,字符串被 分词器 分为单个的词条。一个简单的分词器遇到空格和标点的时候,可能会将文本拆分成词条。
    Token 过滤器
  • 最后,词条按顺序通过每个 token 过滤器 。这个过程可能会改变词条(例如,小写化 Quick ),删除词条(例如, 像 aandthe 等无用词),或者增加词条(例如,像 jumpleap 这种同义词)。

Elasticsearch提供了开箱即用的字符过滤器、分词器和token 过滤器。 这些可以组合起来形成自定义的分析器以用于不同的目的。我们会在 自定义分析器 章节详细讨论。

内置分析器

但是, Elasticsearch还附带了可以直接使用的预包装的分析器。接下来我们会列出最重要的分析器。为了证明它们的差异,我们看看每个分析器会从下面的字符串得到哪些词条:

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

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

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

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

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

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

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

注意看 transparent、 calling 和 set_trans 已经变为词根格式。

什么时候使用分析器

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

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

  • 当你查询一个 全文 域时, 会对查询字符串应用相同的分析器,以产生正确的搜索词条列表。
  • 当你查询一个 精确值 域时,不会分析查询字符串,而是搜索你指定的精确值。

现在你可以理解在 开始章节 的查询为什么返回那样的结果:

  • date 域包含一个精确值:单独的词条 2014-09-15
  • _all 域是一个全文域,所以分词进程将日期转化为三个词条: 2014, 09, 和 15

当我们在 _all 域查询 2014,它匹配所有的12条推文,因为它们都含有 2014

GET /_search?q=2014              # 12 results

当我们在 _all 域查询 2014-09-15,它首先分析查询字符串,产生匹配 201409, 或 15 中 任意 词条的查询。这也会匹配所有12条推文,因为它们都含有 2014

GET /_search?q=2014-09-15        # 12 results !

当我们在 date 域查询 2014-09-15,它寻找 精确 日期,只找到一个推文:

GET /_search?q=date:2014-09-15   # 1  result

当我们在 date 域查询 2014,它找不到任何文档,因为没有文档含有这个精确日志:

GET /_search?q=date:2014         # 0  results !

测试分析器

有些时候很难理解分词的过程和实际被存储到索引中的词条,特别是你刚接触Elasticsearch。为了理解发生了什么,你可以使用 analyze API 来看文本是如何被分析的。在消息体里,指定分析器和要分析的文本:

GET /_analyze
{"analyzer": "standard","text": "Text to analyze"
}

结果中每个元素代表一个单独的词条:

{"tokens": [{"token": "text","start_offset": 0,"end_offset": 4,"type": "<ALPHANUM>","position": 0},{"token": "to","start_offset": 5,"end_offset": 7,"type": "<ALPHANUM>","position": 1},{"token": "analyze","start_offset": 8,"end_offset": 15,"type": "<ALPHANUM>","position": 2}]
}

token 是实际存储到索引中的词条。 position 指明词条在原始文本中出现的位置。 start_offsetend_offset 指明字符在原始字符串中的位置。

每个分析器的 type 值都不一样,可以忽略它们。它们在Elasticsearch中的唯一作用在于​keep_types token 过滤器​。

analyze API 是一个有用的工具,它有助于我们理解Elasticsearch索引内部发生了什么,随着深入,我们会进一步讨论它。

指定分析器

当Elasticsearch在你的文档中检测到一个新的字符串域,它会自动设置其为一个全文 字符串 域,使用 标准 分析器对它进行分析。

你不希望总是这样。可能你想使用一个不同的分析器,适用于你的数据使用的语言。有时候你想要一个字符串域就是一个字符串域—​不使用分析,直接索引你传入的精确值,例如用户ID或者一个内部的状态域或标签。

要做到这一点,我们必须手动指定这些域的映射。

映射

为了能够将时间域视为时间,数字域视为数字,字符串域视为全文或精确值字符串, Elasticsearch 需要知道每个域中数据的类型。这个信息包含在映射中。

如 数据输入和输出 中解释的,索引中每个文档都有 类型 。每种类型都有它自己的 映射 ,或者 模式定义 。映射定义了类型中的域,每个域的数据类型,以及Elasticsearch如何处理这些域。映射也用于配置与类型有关的元数据。

我们会在 类型和映射 详细讨论映射。本节,我们只讨论足够让你入门的内容。

核心简单域类型

Elasticsearch 支持如下简单域类型:

  • 字符串: string
  • 整数 : byte, short, integer, long
  • 浮点数: float, double
  • 布尔型: boolean
  • 日期: date

当你索引一个包含新域的文档—​之前未曾出现-- Elasticsearch 会使用 动态映射 ,通过JSON中基本数据类型,尝试猜测域类型,使用如下规则:

  1. 文本类型(Text):
    • text: 用于索引长文本内容,会进行分词处理并建立倒排索引,适用于全文搜索场景。
    • keyword: 适用于索引关键字或精确值,不进行分词处理,可以用于过滤、排序和聚合等操作。
  2. 数值类型(Numeric):
    • long, integer, short, byte: 用于索引整数类型数据,存储范围不同。
    • double, float: 用于索引浮点数类型数据,精度不同。
  3. 日期类型(Date):
    • date: 用于索引日期时间数据,可以处理不同格式的日期时间字符串。
  4. 布尔类型(Boolean):
    • boolean: 用于索引布尔类型数据,只能存储 true 或 false。
  5. 二进制类型(Binary):
    • binary: 用于索引二进制数据,例如图片、文件等,不进行分析索引。

这意味着如果你通过引号( “123” )索引一个数字,它会被映射为 string 类型,而不是 long 。但是,如果这个域已经映射为 long ,那么 Elasticsearch 会尝试将这个字符串转化为 long ,如果无法转化,则抛出一个异常。

查看映射

通过 /_mapping ,我们可以查看 Elasticsearch 在一个或多个索引中的一个或多个类型的映射。在 开始章节 ,我们已经取得索引 gb 中类型 tweet 的映射:

GET /gb/_mapping

Elasticsearch 根据我们索引的文档,为域(称为 属性 )动态生成的映射。

{"gb": {"mappings": {"tweet": {"properties": {"date": {"type": "date","format": "strict_date_optional_time||epoch_millis"},"name": {"type": "string"},"tweet": {"type": "string"},"user_id": {"type": "long"}}}}}
}

自定义域映射

尽管在很多情况下基本域数据类型已经够用,但你经常需要为单独域自定义映射,特别是字符串域。自定义映射允许你执行下面的操作:

  • 全文字符串域和精确值字符串域的区别
  • 使用特定语言分析器
  • 优化域以适应部分匹配
  • 指定自定义数据格式
  • 还有更多

域最重要的属性是 type 。对于不是 string 的域,你一般只需要设置 type :

{"number_of_clicks": {"type": "integer"}
}

默认, string 类型域会被认为包含全文。就是说,它们的值在索引前,会通过一个分析器,针对于这个域的查询在搜索前也会经过一个分析器。

string 域映射的两个最重要属性是 index 和 analyzer 。

index

index 属性控制怎样索引字符串。它可以是下面三个值:
index=true:

  • 默认值,表示对该字段进行索引,并且进行分词处理。这意味着该字段会被拆分成单词,并建立倒排索引,支持全文搜索和分析。
    index=false:
  • 表示不对该字段进行索引,也不进行分词处理。这样的字段只能进行精确匹配,不支持全文搜索和分析。适用于一些不需要搜索的字段,例如原始 JSON 数据等。
    index=analyzed(已弃用):
  • 表示对该字段进行索引,但不进行分词处理。这个选项已经被弃用,建议使用 index=true 或 index=false。
    index=not_analyzed(已弃用):
  • 表示对该字段进行索引,但不进行分词处理。这个选项已经被弃用,建议使用 index=true 或 index=false。
    index=keyword:
  • 仅适用于 keyword 类型的字段,表示对该字段进行索引,但不进行分词处理。适用于需要精确匹配和聚合操作的关键字字段。
    index=true/false + analyzer:
  • 除了直接设置 index 外,还可以通过设置特定的分析器来控制字段的索引方式。例如,可以使用 “index”: “true”, “analyzer”: “standard” 来对字段进行分词处理。

总之,通过设置 index 属性,可以灵活控制字段的索引方式,根据实际需求选择合适的设置以达到最佳的搜索和分析效果。

需要注意的是,一些选项如 analyzed 和 not_analyzed 已经在较新版本的 Elasticsearch 中被废弃,建议使用更清晰的选项,例如 keyword 类型来代替。

string 域 index 属性默认是 analyzed 。如果我们想映射这个字段为一个精确值,我们需要设置它 type 为 keyword :

{"properties": {"tag": {"type": "keyword"}}
}

其他简单类型(例如 long , double , date 等)也接受 index 参数,但有意义的值只有 no 和 not_analyzed , 因为它们永远不会被分析。

analyzer

对于 analyzed 字符串域,用 analyzer 属性指定在搜索和索引时使用的分析器。默认, Elasticsearch 使用 standard 分析器, 但你可以指定一个内置的分析器替代它,例如 whitespace 、 simple 和 english:

{"tweet": {"type":     "string","analyzer": "english"}
}

在 自定义分析器 ,我们会展示怎样定义和使用自定义分析器。

更新映射

当你首次创建一个索引的时候,可以指定类型的映射。你也可以使用 /_mapping 为新类型(或者为存在的类型更新映射)增加映射。

尽管你可以 增加 一个存在的映射,你不能 修改 存在的域映射。如果一个域的映射已经存在,那么该域的数据可能已经被索引。如果你意图修改这个域的映射,索引的数据可能会出错,不能被正常的搜索。

我们可以更新一个映射来添加一个新域,但不能将一个存在的域从 analyzed 改为 not_analyzed 。

为了描述指定映射的两种方式,我们先删除 gd 索引:

DELETE /gb

然后创建一个新索引,指定 tweet 域使用 english 分析器:

PUT /gb
{"mappings": {"properties": {"tweet": {"type": "text","analyzer": "english"},"date": {"type": "date"},"name": {"type": "text"},"user_id": {"type": "long"}}}
}
  • “mappings” 直接定义了映射的属性,不再嵌套文档类型。
  • “properties” 下列出了索引的字段和其类型信息。
    • “tweet” 字段已经被替换为更加通用的 “text” 类型,用于存储文本数据并应用英文分析器。
    • “date” 字段使用了 “date” 类型,用于存储日期数据。
    • “name” 字段也使用了 “text” 类型,用于存储文本数据。
    • “user_id” 字段使用了 “long” 类型,用于存储长整型数据。
PUT /gb/_mapping
{"properties": {"tag": {"type": "keyword"}}
}

测试映射

你可以使用 analyze API 测试字符串域的映射。比较下面两个请求的输出:

GET /gb/_analyze
{"field": "tweet","text": "Black-cats" 
}GET /gb/_analyze
{"field": "tag","text": "Black-cats" 
}
# GET /gb/_analyze 200 OK
{"tokens": [{"token": "black","start_offset": 0,"end_offset": 5,"type": "<ALPHANUM>","position": 0},{"token": "cat","start_offset": 6,"end_offset": 10,"type": "<ALPHANUM>","position": 1}]
}
# GET /gb/_analyze 200 OK
{"tokens": [{"token": "Black-cats","start_offset": 0,"end_offset": 10,"type": "word","position": 0}]
}

tweet 域产生两个词条 black 和 cat , tag 域产生单独的词条 Black-cats 。换句话说,我们的映射正常工作。

复杂核心域类型

除了我们提到的简单标量数据类型, JSON 还有 null 值,数组,和对象,这些 Elasticsearch 都是支持的。

多值域

很有可能,我们希望 tag 域包含多个标签。我们可以以数组的形式索引标签:

{ "tag": [ "search", "nosql" ]}

对于数组,没有特殊的映射需求。任何域都可以包含0、1或者多个值,就像全文域分析得到多个词条。

这暗示 数组中所有的值必须是相同数据类型的 。你不能将日期和字符串混在一起。如果你通过索引数组来创建新的域,Elasticsearch 会用数组中第一个值的数据类型作为这个域的 类型 。

当你从 Elasticsearch 得到一个文档,每个数组的顺序和你当初索引文档时一样。你得到的 _source 域,包含与你索引的一模一样的 JSON 文档。
但是,数组是以多值域 索引的—可以搜索,但是无序的。 在搜索的时候,你不能指定 “第一个” 或者 “最后一个”。 更确切的说,把数组想象成 装在袋子里的值 。

空域

当然,数组可以为空。这相当于存在零值。 事实上,在 Lucene 中是不能存储 null 值的,所以我们认为存在 null 值的域为空域。

下面三种域被认为是空的,它们将不会被索引:

"null_value":               null,
"empty_array":              [],
"array_with_null_value":    [ null ]

多层级对象

我们讨论的最后一个 JSON 原生数据类是 对象 – 在其他语言中称为哈希,哈希 map,字典或者关联数组。

内部对象 经常用于嵌入一个实体或对象到其它对象中。例如,与其在 tweet 文档中包含 user_name 和 user_id 域,我们也可以这样写:

{"tweet":            "Elasticsearch is very flexible","user": {"id":           "@johnsmith","gender":       "male","age":          26,"name": {"full":     "John Smith","first":    "John","last":     "Smith"}}
}

内部对象的映射

Elasticsearch 会动态监测新的对象域并映射它们为 对象 ,在 properties 属性下列出内部域:

{"gb": {"tweet": { "properties": {"tweet":            { "type": "string" },"user": { "type":             "object","properties": {"id":           { "type": "string" },"gender":       { "type": "string" },"age":          { "type": "long"   },"name":   { "type":         "object","properties": {"full":     { "type": "string" },"first":    { "type": "string" },"last":     { "type": "string" }}}}}}}}
}

user 和 name 域的映射结构与 tweet 类型的相同。事实上, type 映射只是一种特殊的 对象 映射,我们称之为 根对象 。除了它有一些文档元数据的特殊顶级域,例如 _source 和 _all 域,它和其他对象一样。

内部对象是如何索引的

{"tweet":            [elasticsearch, flexible, very],"user.id":          [@johnsmith],"user.gender":      [male],"user.age":         [26],"user.name.full":   [john, smith],"user.name.first":  [john],"user.name.last":   [smith]
}

内部域 可以通过名称引用(例如, first )。为了区分同名的两个域,我们可以使用全 路径 (例如, user.name.first ) 或 type 名加路径( tweet.user.name.first )。

内部对象数组

最后,考虑包含内部对象的数组是如何被索引的。 假设我们有个 followers 数组:

{"followers": [{ "age": 35, "name": "Mary White"},{ "age": 26, "name": "Alex Jones"},{ "age": 19, "name": "Lisa Smith"}]
}

这个文档会像我们之前描述的那样被扁平化处理,结果如下所示:

{"followers.age":    [19, 26, 35],"followers.name":   [alex, jones, lisa, smith, mary, white]
}

{age: 35} 和 {name: Mary White} 之间的相关性已经丢失了,因为每个多值域只是一包无序的值,而不是有序数组。这足以让我们问,“有一个26岁的追随者?”

但是我们不能得到一个准确的答案:“是否有一个26岁 名字叫 Alex Jones 的追随者?”

相关内部对象被称为 nested 对象,可以回答上面的查询,我们稍后会在嵌套对象中介绍它。

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

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

相关文章

如何利用GitHub和jsDelivr托管图片cdn

1、背景 https://cdn.jsdelivr.net/gh/axh2018/axh2018.github.io/medias/banner/6.jpg 这个链接是如何生成的&#xff1f;免费吗&#xff1f; 2、解决 这个链接看起来是使用了 jsDelivr 服务来托管在 GitHub 上的静态文件。jsDelivr 是一个免费的开源 CDN (Content Deliver…

【关于窗口移动求和的两种计算方法】

窗口移动计算方法 例子方法1方法2运行结果: 例子 在很多算法中都会涉及到窗口滑动&#xff0c;比如基于新息序列更新的自适应卡尔曼滤波器算法中便会使用到。 已知一个数列&#xff1a;OCV [1;2;3;4;5;6;7;8;9;10;11;12;13;14;15]&#xff0c;定义窗口长度为5&#xff0c;每次…

小林coding图解计算机网络|TCP篇06|如何理解TCP面向字节流协议、为什么UDP是面向报文的协议、如何解决TCP的粘包问题?

小林coding网站通道&#xff1a;入口 本篇文章摘抄应付面试的重点内容&#xff0c;详细内容还请移步&#xff1a;小林coding网站通道 文章目录 如何理解UDP 是面向报文的协议如何理解字节流如何解决粘包固定长度的消息 特殊字符作为边界自定义消息结构 如何理解UDP 是面向报文的…

MFC中数据转化

目录 1.CString数据转化为int类型数据 2.int类型转化为CString类型数据 3.MFC中CString数据类型 转换为std::string数据类型 4.MFC中std::string数据类型 转换为CString数据类型 1.CString数据转化为int类型数据 在MFC中&#xff0c;将CString类型数据转换为int类型数据&a…

Hadoop-入门

资料来源&#xff1a;尚硅谷-Hadoop 一、Hadoop 概述 1.1 Hadoop 是什么 1&#xff09;Hadoop是一个由Apache基金会所开发的分布式系统基础架构。 2&#xff09;主要解决&#xff1a;海量数据的存储和海量数据的分析计算问题。 3&#xff09;广义上来说&#xff0c;Hadoop…

数据结构--最长公共前缀

数据结构–最长公共前缀 方法一&#xff1a; 分析 首先找到最小长度的字符串&#xff0c;然后把其与每一个与每一个字符串查找索引&#xff0c;判断其是不是第一个(索引为0)&#xff0c;若其是&#xff0c;则计数的加一&#xff0c;当计数等于字符数组长度&#xff0c;即每个…

深入浅出 -- 系统架构之分布式常见理论概念

随着计算机科学和互联网的发展&#xff0c;分布式场景变得越来越常见&#xff0c;能否处理好分布式场景下的问题&#xff0c;成为衡量一个工程师是否合格的标准。本文我们介绍下分布式系统相关的理论知识&#xff0c;这些理论是我们理解和处理分布式问题的基础。 CAP理论 CAP…

深入理解选择排序:算法原理、Java实现与性能优劣

算法学习的重要性 在程序员的世界里&#xff0c;算法就如同一座桥梁&#xff0c;连接着问题与解决方案&#xff0c;是实现优秀程序的关键。 掌握算法&#xff0c;就能够在面对各种问题时&#xff0c;找到最合适的解决方法&#xff0c;以最少的时间和空间&#xff0c;实现最优的…

Android数据存储技术

一、文件存储 <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:orientation"vertical"android:layout_width"match_parent"android:layout_height"match_parent" ><EditTextandroid:id&qu…

mac 切换 jdk

查看 mac 上都有哪些版本 /usr/libexec/java_home -V看准版本切换 按前缀切换 比如 export JAVA_HOME/usr/libexec/java_home -v 1.8这样会随机一个 1.8 的 如果想再确定一个比如 openjdk export JAVA_HOME/usr/libexec/java_home -v 1.8.0_292这个方式是临时的&#xff0c…

【力扣刷题日记】1421.净现值查询

前言 练习sql语句&#xff0c;所有题目来自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免费数据库练习题。 今日题目&#xff1a; 1421.净现值查询 表&#xff1a;NPV 列名类型idintyearintnpvint (id, year) 是该表主键(具有唯一值的列的…

用友NC Cloud importhttpscer 任意文件上传漏洞复现

0x01 产品简介 用友 NC Cloud 是一种商业级的企业资源规划云平台,为企业提供全面的管理解决方案,包括财务管理、采购管理、销售管理、人力资源管理等功能,基于云原生架构,深度应用新一代数字技术,打造开放、 互联、融合、智能的一体化云平台,支持公有云、混合云、专属云…

AI绘画:实例-利用Stable Diffusion ComfyUI实现多图连接:区域化提示词与条件设置

在Stable Diffusion ComfyUI中&#xff0c;有一种高级技巧可以让用户通过细致的区域化提示词来控制图像的不同部分&#xff0c;从而实现多图连接的效果。这种方法允许艺术家在同一画布上展现多个场景&#xff0c;创造出富有层次和故事性的图像。以下是实现这一效果的详细步骤。…

Leetcode链表刷题总结(Java版)

链表 1、移除链表元素&#xff08;考虑全情况&#xff09; 问题需求&#xff1a;根据给定的val值&#xff0c;移除链表中值是这个val的节点 203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 这里有一个问题就是&#xff0c;如果需要被移除的节点不是中间的某个节点…

Tuxera2023 NTFS for Mac下载,安装和序列号激活

对于必须在Windows电脑和Mac电脑之间来回切换的Mac朋友来说&#xff0c;跨平台不兼容一直是一个巨大的障碍&#xff0c;尤其是当我们需要使用NTFS格式的硬盘在Windows和macOS之间共享文件时。因为Mac默认不支持写入NTFS磁盘。 为了解决这一问题&#xff0c;很多朋友会选择很便捷…

【Java基础知识总结 | 第十篇】HashSet底层实现原理

文章目录 10.HashSet底层实现原理10.1HashSet特点10.2HashSet源码10.3 add流程10.4总结 10.HashSet底层实现原理 10.1HashSet特点 存储对象&#xff1a;HashSet 存储对象采用哈希表的方式&#xff0c;它不允许重复元素&#xff0c;即集合中不会包含相同的元素。当向 HashSet …

使用Ajax的优点

Ajax的优点主要表现在以下几个方面&#xff1a; 1. 页面无刷新&#xff1a;Ajax可以在不更新整个页面的前提下与服务器通信&#xff0c;维护数据&#xff0c;给用户的体验非常好。 2. 异步通信&#xff1a;Ajax使用异步方式与服务器通信&#xff0c;不需要打断用户的操作&#…

数据挖掘中的PCA和KMeans:Airbnb房源案例研究

目录 一、PCA简介 二、数据集概览 三、数据预处理步骤 四、PCA申请 五、KMeans 聚类 六、PCA成分分析 七、逆变换 八、质心分析 九、结论 十、深入探究 10.1 第 1 步&#xff1a;确定 PCA 组件的最佳数量 10.2 第 2 步&#xff1a;使用 9 个组件重做 PCA 10.3 解释 PCA 加载和特…

【微服务】------核心组件架构选型

1.微服务简介 微服务架构&#xff08;Microservice Architecture&#xff09;是一种架构概念&#xff0c;旨在通过将功能分解到各个离散的服务中以实现对解决方案的解耦&#xff0c;从而降低系统的耦合性&#xff0c;并提供更加灵活的服务支持。 2.微服务技术选型 区域内容…

Kotlin学习日志(一)TextView、Button、Toast的使用(1)

android:layout_width“wrap_content” android:layout_height“wrap_content”/> import kotlinx.android.synthetic.main.activity_main.* 这句话的意思是引进Kotlin的的控件变量自动映射功能&#xff0c;接下来只要是这个activity_main.xml文件中的控件&#xff0c;我…