Elasticsearch:高级数据类型介绍

在我之前的文章 “Elasticsearch:一些有趣的数据类型”,我已经介绍了一下很有趣的数据类型。在今天的文章中,我再进一步介绍一下高级的数据类型,虽然这里的数据类型可能和之前的一些数据类型有所重复。即便如此,我希望能从另外的一个方面来描述这些数据类型。希望大家能在自己的应用中熟练地运用这些数据类型。 

Geopoint(geo_point)数据类型

我们中的大多数人可能在圣诞节期间使用过智能设备来查找最近的餐馆的位置,或者询问过 GPS 导航到我们奶奶家的方向。 Elasticsearch 开发了一种专门的数据类型 geo_point 用于捕获地点的位置。

位置数据表示为 geo_point 数据类型,表示经度和纬度。 我们可以使用它来确定餐厅、学校、高尔夫球场等的地址。

下面显示的代码清单演示了名为 restaurants 的索引的模式定义。 它保护带有名称和地址的餐馆。 值得注意的是,地址字段被定义为 geo_point 数据类型:

# A restaurants index with address declared as geo_point
PUT restaurants
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "address": {
        "type": "geo_point"
      }
    }
  }
}

现在我们有了一个索引,让我们索引一个示例餐厅(位于伦敦的虚构 Sticky Fingers),其位置以经度和纬度形式提供(列表如下):

# Indexing a restaurant - the location is provided as lon and lat
PUT restaurants/_doc/1
{
  "name": "Sticky Fingers",
  "address": {
    "lon": "0.1278",
    "lat": "51.5074"
  }
}

在上面的代码片段中,餐厅的地址以经度 (lon) 和纬度 (lat) 对的形式提供。 还有其他方法可以提供这些输入,我们稍后会介绍。上面的位置使用 Elastic Maps 可以显示如下:

我们无法搜索和获取周边位置内的餐厅。 我们可以使用 geo_bounding_box 查询来搜索涉及地理地址的数据。 它需要输入 top_left 和 bottom_right 点来围绕我们的兴趣点创建一个框起来的区域,如下图所示

我们使用 lon(经度)和 lat(纬度)对(地址位置指向伦敦)为该查询提供上限和下限。我们编写 geo_bounding_box 查询以矩形的形式提供地址,其中 top_left 和 bottom_right 坐标以纬度和经度提供,如下面的清单所示

# Listing to Fetch the restaurants around a geographical location
GET restaurants/_search?filter_path=**.hits
{
  "query": {
    "geo_bounding_box": {
      "address": {
        "top_left": {
          "lon": "0",
          "lat": "52"
        },
        "bottom_right": {
          "lon": "1",
          "lat": "50"
        }
      }
    }
  }
}

此查询获取我们的餐厅,因为地理边界框包含我们的餐厅:

{
  "hits": {
    "hits": [
      {
        "_index": "restaurants",
        "_id": "1",
        "_score": 1,
        "_source": {
          "name": "Sticky Fingers",
          "address": {
            "lon": "0.1278",
            "lat": "51.5074"
          }
        }
      }
    ]
  }
}

正如我之前提到的,我们可以提供各种格式的位置信息,而不仅仅是纬度和经度:例如,数组或字符串。 下表提供了创建位置数据的方法和示例:

更多关于 geo_point 的搜索,请参考:

  • Elastic:开发者上手指南 中的 “Maps” 章节

  • 开始使用 Elasticsearch (2)

对象数据类型 - object data type

我们经常以分层方式查找数据,例如一封电子邮件,其中包含顶级字段,如 subject、to 和 from 字段以及用于保存附件的内部对象,如下面的代码片段所示:

"to:":"johndoe@johndoe.com",   
 "subject":"Testing Object Type",   
 "attachments":{     
  "filename":"file1.txt",     
  "filetype":"confidential"   
 }


JSON 允许我们创建这样的分层对象:一个包含在其他对象中的对象。 为了表示这种对象层次结构,Elasticsearch 有一种特殊的数据类型来表示对象的层次结构 —— 对象类型。 在上面的示例中,由于附件(attachments)包含其他属性,我们将其归类为对象本身,因此属于对象类型。 attachments 对象中的 filename 和 filetype 这两个属性可以分别建模为 text 和 text 字段。 有了这些信息,我们就可以创建一个映射定义,如下面的清单所示:

# Defining the attatchments as object type. Though we can set the type as object speficially, Elasticsearch is clever enough to deduce it as an object type when it sees hierarchical data sets. Hence we can omit declaring the object type
PUT emails
{
  "mappings": {
    "properties": {
      "to": {
        "type": "text"
      },
      "subject": {
        "type": "text"
      },
      "attachments": {
        "type":"object",
        "properties": {
          "filename": {
            "type": "text"
          },
          "filetype": {
            "type": "text"
          }
        }
      }
    }
  }
}

attachments 字段是一个对象,因为它封装了其他两个字段。 虽然我们已经明确提到类型是 object,但 Elasticsearch 并不期望我们这样做。 每当遇到具有分层数据的字段时,它将字段的数据类型设置为 object。我们其实甚至可以省去 "type": "object" 这一行。

模式成功执行后,我们可以通过调用 GET emails/_mapping 命令来检索它(清单如下):

GET emails/_mapping
# The mapping schema for emails
# The attachments type is not listed (inferred as object by Elasticsearch!)
{
  "emails" : {
    "mappings" : {
      "properties" : {
        "attachments" : {
          "properties" : {
            "filename" : {"type" : "text"},
            "filetype" : {"type" : "text"}
          }
        },
        "subject" : {"type" : "text"},
        "to" : {"type" : "text"}
      }
    }
  }
}

虽然所有其他字段都显示其关联的数据类型,但 attachments 不会。 内部对象的对象类型由 Elasticsearch 默认推断。 让我们索引一个电子邮件文档,下面给出的清单显示了查询:

#Indexing an email document
PUT emails/_doc/1
{
  "to:": "johndoe@johndoe.com",
  "subject": "Testing Object Type",
  "attachments": {
    "filename": "file1.txt",
    "filetype": "confidential"
  }
}

现在我们已经用文档准备好我们的电子邮件索引,我们可以在内部对象字段上发出匹配搜索查询(我们将在接下来的文章中了解搜索查询)以获取相关文档(并证明我们的观点),如清单如下:

# Searching for an email based on the attachment name
GET emails/_search?filter_path=**.hits
{
  "query": {
    "match": {
      "attachments.filename": "file1.txt"
    }
  }
}

上面命令的响应为:

{
  "hits": {
    "hits": [
      {
        "_index": "emails",
        "_id": "1",
        "_score": 0.5753642,
        "_source": {
          "to:": "johndoe@johndoe.com",
          "subject": "Testing Object Type",
          "attachments": {
            "filename": "file1.txt",
            "filetype": "confidential"
          }
        }
      }
    ]
  }
}

这将从我们的 Elasticsearch 返回文档,因为 filename 与我们在 Elasticsearch 中的文档相匹配。

虽然对象类型非常简单,但它们有一个局限性:内部对象被扁平化并且不存储为单独的文档。 此操作的缺点是从数组索引的对象之间的关系丢失。 好消息是我们有另一种称为嵌套(nested)数据的数据类型来解决这个问题。

遗憾的是,由于篇幅所限,我无法在此处介绍对象的局限性 —— 你可以在 “Elasticsearch: object 及 nested 数据类型” 做更进一步的阅读。

嵌套数据类型 - nested data type

嵌套数据类型是对象类型的特殊形式,其中维护文档中对象数组之间的关系。

以我们的电子邮件和附件为例,这次让我们将附件字段定义为 nested 数据类型,而不是让 Elasticsearch 将其派生为对象类型。 这需要通过将附件字段声明为 nested 数据类型来创建模式。 该模式显示在下面给出的清单中:

# Creating the attachments field as nested datatype
PUT emails_nested
{
  "mappings": {
    "properties": {
      "attachments": {
        "type": "nested",
        "properties": {
          "filename": {
            "type": "keyword"
          },
          "filetype": {
            "type": "text"
          }
        }
      }
    }
  }
}

我们已经创建了一个模式(schema)定义,所以我们需要做的就是索引一个文档。 下面给出的清单正是这样做的:

# Indexing a document with attachments 
PUT emails_nested/_doc/1
{
  "attachments": [
    {
      "filename": "file1.txt",
      "filetype": "confidential"
    },
    {
      "filename": "file2.txt",
      "filetype": "private"
    }
  ]
}

一旦该文档被成功索引,拼图的最后一块就是搜索。 下面的清单将演示为获取文档而编写的搜索查询——标准是带有 file1.txt 附件的电子邮件和 private 分别作为文件名及其分类类型。 这种组合不存在,因此结果必须为空,这与交叉搜索数据的 object 不同。

# This query shoulnd't return resutls as we don't have file name as "file1.txt" and type as "private" data (look at the document above)
GET emails_nested/_search
{
  "query": {
    "nested": {
      "path": "attachments",
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "attachments.filename": "file1.txt"
              }
            },
            {
              "match": {
                "attachments.filetype": "private"
              }
            }
          ]
        }
      }
    }
  }
}

上面清单中的查询正在搜索一个名为 file1.txt 的文件,该文件具有不存在的 private 分类(查看我们之前索引的文档)。 此查询没有返回任何文档,这正是我们所期望的。 file1.txt 的分类是 confidential 的而不是 private 的,因此它不匹配。 因此,当 nested 类型表示内部对象数组时,单个对象将作为隐藏文档进行存储和索引。

Nested 数据类型非常擅长尊重关联和关系,因此如果我们需要创建一个对象数组,其中每个对象都必须被视为一个单独的对象,nested 数据类型将成为我们的朋友。

更多阅读,请参阅   “Elasticsearch: object 及 nested 数据类型”。

没有数组类型

当我们谈到数组时,有趣的是,Elasticsearch 中没有数组数据类型。 但是,我们可以为任何字段设置多个值,从而将字段表示为一个数组。 例如,具有一个 name 字段的文档可以从单个值更改为数组:"name": "John Doe" 到 "name": ["John Smith", "John Doe"] 只需添加一个列表数据值到字段。 创建数组时必须考虑一个重点:不能将数组与各种类型混在一起。 例如,你不能像这样声明 name 字段:"name": ["John Smith", 13, "Neverland"]。 这是非法的,因为该字段由多种类型组成,是不允许的。

Flattened(扁平化)数据类型

到目前为止,我们已经研究了对从 JSON 文档解析的各个字段建立索引。 在分析和存储时,每个字段都被视为一个单独且独立的字段。 然而,有时我们可能不需要将所有子字段作为单独的字段进行索引,从而让它们通过分析过程。 想一想聊天系统上的聊天消息流、现场足球比赛中的评论、医生记录病人的病痛等等。 我们可以将这种数据作为一个大 blob 加载,而不是显式声明每个字段(或动态派生)。 Elasticsearch 为此提供了一种称为扁平化的特殊数据类型。

flattened 数据类型以一个或多个子字段的形式保存信息,每个子字段的值作为关键字索引。 也就是说,没有一个值被视为文本字段,因此不经过文本分析过程。更多关分析方面的知识,请参考文章 “Elasticsearch: analyzer”。

让我们考虑一个医生在咨询期间记录他/她的病人的运行笔记的例子。 该映射由两个字段组成:患者 name 和 doctor_notes - doctor_notes 字段被声明为 flattened 类型。 下面给出的清单提供了映射:

# Listing for Creating a mapping with flattened data type
PUT consultations
{
  "mappings": {
    "properties": {
      "patient_name": {
        "type": "text"
      },
      "doctor_notes": {
        "type": "flattened"
      }
    }
  }
}

任何声明为 flattened 的字段(及其子字段)都不会被分析。 即所有的值都被索引为 keyword。 让我们创建一个患者咨询文档(在下面列出)并为其编制索引:

# The consultation document with doctor’s notes
PUT consultations/_doc/1
{
  "patient_name": "John Doe",
  "doctor_notes": {
    "temperature": 103,
    "symptoms": [
      "chills",
      "fever",
      "headache"
    ],
    "history": "none",
    "medication": [
      "Antibiotics",
      "Paracetamol"
    ]
  }
}

如你所见,doctor_notes 包含大量信息,但请记住我们并未在映射定义中创建这些内部字段。 由于doctor_notes是一个 flattened 的类型,所以所有的值都被索引为 keyword。

最后,我们使用医生笔记中的任何关键字搜索索引,如下所示:

# Searching for patients prescribed with paracetomol
GET consultations/_search?filter_path=**.hits
{
  "query": {
    "match": {
      "doctor_notes": "Paracetamol"
    }
  }
}

上面命令返回的结果为:

{
  "hits": {
    "hits": [
      {
        "_index": "consultations",
        "_id": "1",
        "_score": 0.44303042,
        "_source": {
          "patient_name": "John Doe",
          "doctor_notes": {
            "temperature": 103,
            "symptoms": [
              "chills",
              "fever",
              "headache"
            ],
            "history": "none",
            "medication": [
              "Antibiotics",
              "Paracetamol"
            ]
          }
        }
      }
    ]
  }
}

搜索 Paracetamol 将返回我们的 John Doe 的咨询文件。 你可以通过将匹配查询更改为任何字段来进行试验,例如:"doctor_notes": "chills" 或者甚至编写如下所示的复杂查询:

#An advanced query to fetch patients based on multiple search criteria
# Search for non-diabetic patients with headache and prescribed with antibiotcs
GET consultations/_search?filter_path=**.hits
{   
 "query": {      
  "bool": {       
   "must": [{"match": {"doctor_notes": "headache"}},        
    {"match": {"doctor_notes": "Antibiotics"}}],       
    "must_not": [{"term": {"doctor_notes": {"value": "diabetics"}}}] 
  }   
 } 
}

在查询中,我们检查 headaches (头痛)和 antibiotics(抗生素),但患者不应该患有 diabetic(糖尿病)—— 查询返回 John Doe,因为他没有糖尿病但有头痛并且正在服用抗生​​素(快点好起来,Doe!)。

Flattened 的数据类型会派上用场,尤其是当我们期望有很多临时的字段并且必须事先为所有字段定义映射定义是不可行的时候。 请注意,flattened 字段的子字段始终是 keyword 类型。

更多关于 flattened 数据类型的内容,请阅读文章 “Elasticsearch:Flattened 数据类型映射”。

Join 数据类型

如果你来自关系数据库世界,你就会知道数据之间的关系 —— joins —— 支持父子关系。 然而,在 Elasticsearch 中,每个被索引的文档都是独立的,并且与该索引中的任何其他文档都没有关系。 Elasticsearch 对数据进行反规范化,以在索引和搜索操作期间提高速度和性能。 Elasticsearch 提供了一个 join 数据类型来考虑我们需要的父子关系。

考虑一个医患(一对多)关系的例子:一个医生可以有多个病人,每个病人被分配给一个医生。

让我们创建一个 doctors 索引,其中包含一个包含关系定义的模式。 要使用 join 数据类型处理父子关系,我们需要

  • 创建一个 join 类型的字段和
  • 通过提及 relations 的关系对象添加附加信息(例如,当前上下文中的医患关系)

如下命令准备具有模式定义的 doctors 索引:

# Creating an indx with join datatype - make sure you create a field with the name "relations"
PUT doctors
{
  "mappings": {
    "properties": {
      "relationship": {
        "type": "join",
        "relations": {
          "doctor": "patient"
        }
      }
    }
  }
}

一旦我们准备好模式并建立索引,我们就会索引两种类型的文档:一种代表 doctor(父),另一种代表 patient(子)。 这是医生的文件,其中提到了作为医生的关系:

#Indexing a doctor - make sure the relationship field is set to doctor type
PUT doctors/_doc/1
{
  "name": "Dr Mary Montgomery",
  "relationship": {
    "name": "doctor"
  }
}

上面代码片段中值得注意的一点是关系对象将文档类型声明为 doctor。 name 属性必须是在 relations 标记下的映射模式中声明的父值 (doctor)。 一旦我们的住院医生 Mary Montgomery 医生准备就绪,下一步就是让两名患者与她联系。 以下查询(下面列出)执行此操作:

# Listing for Creating two patients for our doctor
PUT doctors/_doc/2?routing=mary  
{
  "name": "John Doe",
  "relationship": {
    "name": "patient",
    "parent": 1
  }
}
 
PUT doctors/_doc/3?routing=mary 
{
  "name": "Mrs Doe",
  "relationship": {
    "name": "patient",
    "parent": 1
  }
}

关系对象的值应设置为 patient(还记得模式中关系属性的父子部分吗?)并且应该为父对象分配关联医生的文档标识符(在我们的示例中为 ID 1)。

在处理父子关系时,我们还需要了解一件事。 父母和相关的孩子将被索引到同一个分片中,以避免多分片搜索开销。 由于文档应该共存,我们需要在 URL 中使用强制 routing 参数。 路由是一个函数,可以确定文档所在的分片。

最后,是时候搜索属于 ID 为 1 的医生的患者了。下面列表中的查询搜索与 Montgomery 医生相关的所有患者:

# Searching for all patients of Dr Montgomery
GET doctors/_search?filter_path=**.hits
{
  "query": {
    "parent_id": {
      "type": "patient",
      "id": 1
    }
  }
}

上面的响应为:

{
  "hits": {
    "hits": [
      {
        "_index": "doctors",
        "_id": "2",
        "_score": 0.10536051,
        "_routing": "mary",
        "_source": {
          "name": "John Doe",
          "relationship": {
            "name": "patient",
            "parent": 1
          }
        }
      },
      {
        "_index": "doctors",
        "_id": "3",
        "_score": 0.10536051,
        "_routing": "mary",
        "_source": {
          "name": "Mrs Doe",
          "relationship": {
            "name": "patient",
            "parent": 1
          }
        }
      }
    ]
  }
}

当我们希望获取属于医生的患者时,我们使用一个名为 parent_id 的搜索查询,该查询需要子类型(患者)和父 ID(Montgomery 医生文档 ID 为 1)。 该查询将返回 Montgomery 医生的患者 —— Doe 先生和夫人。

使用 join 数据类型并不是直截了当的,因为我们要求非关系数据存储引擎处理关系 —— 有点要求太多,所以只有在你必须的时候才使用 join 数据类型。

在 Elasticsearch 中实现父子关系会对性能产生影响。 如果你正在考虑文档关系,Elasticsearch 可能不是合适的工具,因此请谨慎使用此功能。

更多阅读,请参阅

  • Elasticsearch: Join 数据类型
  • Elasticsearch:在 Elasticsearch 中的 join 数据类型父子关系

Search as you type 数据类型

当我们在搜索栏中键入时,大多数搜索引擎会建议单词和短语。 这个功能有几个名字 —— 通常有几个名字:搜索即输入或预先输入或自动完成或建议。 Elasticsearch 提供了一种方便的数据类型 —— search_as_you_type —— 来支持这个特性。 在幕后,Elasticsearch 非常努力地确保标记为 search_as_you_type 的字段被索引以生成 n-gram,我们将在本节中看到它的实际应用。

n-gram 是给定大小的单词序列。 例如,如果单词是 “action”,则 3-ngram(大小为 3 的 ngram)是:["act", "cti","tio","ion"] 和 bi-grams(大小为 2)是: [“ac”、“ct”、“ti”、“io”、“on”] 等。

另一方面,edge n-gram 是每个单词的 n-gram,其中 n-gram 的开头锚定到单词的开头。 以 “action” 这个词为例,边 n-gram 产生:["a","ac","act","acti","actio","action"]。

另一方面,Shingles 是单词 n-gram。 例如 “Elasticsearch in Action” 这句话会输出:["Elasticsearch", "Elasticsearch in", "Elasticsearch in Action", "in", "in Action", "Action"]

更多阅读:Elasticsearch: Ngrams, edge ngrams, and shingles

比如说,我们被要求支持对 books 索引的预输入查询,即,当用户开始在搜索栏中逐字输入书名时,我们应该能够根据他/她输入的字母推荐这本书 .

首先,我们需要创建一个模式,其中所讨论的字段是 search_as_you_type 数据类型。 下面的列表提供了这个映射模式:

# Mapping schema for technical books with the title defined as search_as_you_type datatype
PUT tech_books
{
  "mappings": {
    "properties": {
      "title": {
        "type": "search_as_you_type"
      }
    }
  }
}

我们现在索引几本书:

# Indexing few documents
PUT tech_books/_doc/1
{
  "title": "I love Elasticsearch technology"
}  
 
PUT tech_books/_doc/2 
{   
 "title":"Elasticsearch is the most popular search engine in the world" 
}

PUT tech_books/_doc/3 
{   
 "title":"Elastic is the company behind Elasticsearch" 
}

由于 title 字段的类型是 search_as_you_type 数据类型,因此 Elasticsearch 在根字段(title)之外创建了一组称为 n-gram 的子字段,如下表所示:

显示引擎自动创建的子字段的表格

由于这些字段是为我们额外创建的,因此在该字段上搜索有望返回预输入建议,因为 n-gram 有助于有效地生成它们。

让我们创建搜索查询,如下面的清单所示。

# Searching in a search_as_you_type field and its subfields
GET tech_books/_search?filter_path=**.hits
{
  "query": {
    "multi_match": {
      "query": "elas",
      "type": "bool_prefix",
      "fields": [
        "title",
        "title._2gram",
        "title._3gram"
      ]
    }
  }
}

上面命令显示的结果是:

{
  "hits": {
    "hits": [
      {
        "_index": "tech_books",
        "_id": "1",
        "_score": 1,
        "_source": {
          "title": "Elasticsearch in Action"
        }
      },
      {
        "_index": "tech_books",
        "_id": "3",
        "_score": 1,
        "_source": {
          "title": "Elastic Stack in Action"
        }
      }
    ]
  }
}

此查询应返回所有的 3 个文档。 我们使用多重匹配查询,因为我们正在跨多个字段搜索一个值 —— title、title._2gram、title._3gram、title._index_prefix。

{
  "hits": {
    "hits": [
      {
        "_index": "tech_books",
        "_id": "1",
        "_score": 1,
        "_source": {
          "title": "I love Elasticsearch technology"
        }
      },
      {
        "_index": "tech_books",
        "_id": "2",
        "_score": 1,
        "_source": {
          "title": "Elasticsearch is the most popular search engine in the world"
        }
      },
      {
        "_index": "tech_books",
        "_id": "3",
        "_score": 1,
        "_source": {
          "title": "Elastic is the company behind Elasticsearch"
        }
      }
    ]
  }
}

更多关于 search_as_you_type 的介绍,请参阅文章 “Elasticsearch:使用 search_analyzer 及 edge ngram 来实现 Search-As-You-Type”。

总结

在本文中,我们学习了高级数据类型,如 object、nested、flattened 以及其他如 geo_point 和 search_as_you_type。 有关其他数据类型的更多详细信息以及深入的讨论和代码示例,请详细参阅 “Elastic:开发者上手指南”。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL数据同步ES的常用思路和方法

文章目录 1.同步双写2.异步双写3.定时任务4.数据订阅大家应该都在各种电商网站检索过商品,检索商品一般都是通过什么实现呢?搜索引擎Elasticsearch。 那么问题来了,商品上架,数据一般写入到MySQL的数据库中,那么用于检索的数据又是怎么同步到Elasticsearch的呢? 1.同步双…

认识Spring(下)

作者:~小明学编程 文章专栏:Spring框架 格言:热爱编程的,终将被编程所厚爱。 目录 Spring更加高效的读取和存储对象 存储bean对象 五大注解 关于五大类注解 对象的注入 属性注入 构造方法注入 Setter注入 三种注入方式的…

IPV6 资料收集

IPV6与IPV4区别 1、地址长度的区别:IPv4协议具有32位(4字节)地址长度;IPv6协议具有128位(16字节)地址长度。 2、地址的表示方法区别:IPv4地址是以小数表示的二进制数。 IPv6地址是以十六进制表…

4.1 读写不同数据源的数据

4.1 读写不同数据源的数据4.1.1 读写数据库数据1、数据库数据获取2、数据库数据存储4.1.2 读写文本文件1、文本文件读取2、文本文件存储4.1.3 读写Excel文件1、Excel文件读取2、Excel文件存储完整代码4.1.1 读写数据库数据 1、数据库数据获取 pandas提供了读取与存储关系型数…

为什么说网络安全行业是 IT 行业最后的红利?

一、为什么选择网络安全? 这几年随着我国《国家网络空间安全战略》《网络安全法》《网络安全等级保护 2.0》等一系列政策/法规/标准的持续落地,网络安全行业地位、薪资随之水涨船高。 未来 3-5 年,是安全行业的黄金发展期,提前踏…

Android OKHttp源码解析

Https是Http协议加上下一层的SSL/TSL协议组成的,TSL是SSL的后继版本,差别很小,可以理解为一个东西。进行Https连接时,会先进行TSL的握手,完成证书认证操作,产生对称加密的公钥、加密套件等参数。之后就可以…

jenkins打包发布前端项目

1.配置前端nodejs打包环境 1.1安装nodejs插件 1.2配置jenkins nodejs环境 2.下载git插件(使用此插件配置通过gitlab标签拉取项目) 3.创建一个自由风格的发布项目 4.配置项目构建流程 4.1添加钉钉告警 4.2配置参数化构建 4.3配置源码管理为git拉取项目 4.4配置构建环境 4.5配置…

Graphic Game(思维 + 模拟删点)

C-Graphic Game_2022年江西省大学生程序设计竞赛(正式赛) (nowcoder.com) Topic describes eightCirno被推荐了一个游戏,她决定今天和Daiyousei一起玩。最初,有一个具有2 n个顶点和m条边的图。在每一个转弯,Cirno和Da…

SpringBoot+Shiro框架整合实现前后端分离的权限管理基础Demo

记录一下使用SpringBoot集成Shiro框架实现前后端分离Web项目的过程,后端使用SpringBoot整合Shiro,前端使用vueelementUI,达到前后端使用token来进行交互的应用,这种方式通常叫做无状态,后端只需要使用Shiro框架根据前端…

【云原生进阶之容器】第五章容器运行时5.4--容器运行时之Firecracker

1 Firecracker诞生背景 近些年 AWS 非常推崇无服务器模式

用Cmake构建第一个C++项目

ps:由于工作需求,需要涉及到跨平台。 概念 Cmake是一个款平台的构建工具,可以自动生成各种不同平台和编译器的构建脚本,使得项目在不同平台和编译器下都能够正常构建和运行。 CMake有自己的一套语法,需要学习CMake的…

上海亚商投顾:两市成交创年内新高 人工智能再爆发

上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。 市场情绪三大指数今日高开高走,沪指震荡反弹逼近3300点,创业板指午后涨超1.7%,科创50指数…

springboot 配置文件、多环境配置、运行优先级

前言 提问:springboot项目,开发环境、测试环境和生产环境配置文件如何分开表示? 答:多profile文件方式 1、多环境配置(profile) 1.1、properties文件配置 application.properties:主配置文…

基于html+css的between布局

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

【算法系列之动态规划IV】完全背包

完全背包 解题思路 01背包的核心思路&#xff0c;为了保证每个物品仅被添加一次&#xff0c;01背包内嵌的循环是从大到小遍历。 for(int i 0; i < weight.size(); i) { // 遍历物品for(int j bagWeight; j > weight[i]; j--) { // 遍历背包容量dp[j] max(dp[j], dp…

【云原生】k8s集群命令行工具kubectl之应用部署命令详解

kubectl应用部署命令详解一、准备工作1.1、Replication Controller1.2、Deployment1.3、DaemonSet1.4、查看创建的svc和pod1.5、kubectl 命令自动补全设置二、应用部署命令2.1、diff2.2、apply2.3、replace2.4、rollout2.4.1、history2.4.2、pause2.4.3、resume2.4.4、restart2…

Java 常量池分析

Java常量池 常量池&#xff1a;存放所有常量 常量池是Class文件中内容最为丰富的区域。常量池对于Class文件中的字段和方法解析也有着至关重要的作用。 随着Java虚拟机的不断发展&#xff0c;常量池的内容也日渐丰富。可以说&#xff0c;常量池是整个Class文件的基石。 在版…

HMC717ALP3E-ASEMI代理ADI(亚德诺)车规级芯片HMC717ALP3E

编辑-Z HMC717ALP3E参数描述&#xff1a; 频率范围&#xff1a;4.8 - 6.0GHz 增益&#xff1a;12.5dB 噪声系数&#xff1a;1.3dB 输入回波损耗&#xff1a;8dB 输出回波损耗&#xff1a;13dB 1 dB压缩的输出功率&#xff08;P1dB&#xff09;&#xff1a;12dBm 饱和输…

2023首届大学生算法大赛 - 村庄

读题可以发现&#xff0c;如果两个村庄不能互相连通&#xff0c;那就算作一对 &#xff08;a<b&#xff09;。 显然是可以用floyd全局多源最短路来做的&#xff0c;如果不存在最短路&#xff0c;那么就是不能互通&#xff0c;但是这道题的数据范围N<10^5&#xff0c;跑f…

SpringCloud之Eureka原理分析与实战(注册与发现)

目录 1、从本质理解服务治理思想 2、为什么选择Spring Cloud服务治理组件 3、Spring Cloud Eureka服务发现 3.1 Eureka的优势 3.2 Eureka架构组成 3.3 搭建Eureka Server 实战 3.3.1 添加依赖 3.3.2 开启服务注册 3.3.3 添加YML配置 3.3.4 访问服务 3.4 搭建Eureka …
最新文章