elasticsearch 笔记三:查询建议介绍、Suggester、自动完成

news2024/11/24 4:50:03

一、查询建议介绍

1. 查询建议是什么?

查询建议,为用户提供良好的使用体验。主要包括: 拼写检查; 自动建议查询词(自动补全)

拼写检查如图:

自动建议查询词(自动补全):

2. ES 中查询建议的 API

查询建议也是使用_search 端点地址。在 DSL 中 suggest 节点来定义需要的建议查询

示例 1:定义单个建议查询词

POST twitter/_search
{
  "query" : {
    "match": {
      "message": "tring out Elasticsearch"
    }
  },
  "suggest" : { <!-- 定义建议查询 -->
    "my-suggestion" : { <!-- 一个建议查询名 -->
      "text" : "tring out Elasticsearch", <!-- 查询文本 -->
      "term" : { <!-- 使用词项建议器 -->
        "field" : "message" <!-- 指定在哪个字段上获取建议词 -->
      }
    }
  }
}

示例 2:定义多个建议查询词

POST _search
{
  "suggest": {
    "my-suggest-1" : {
      "text" : "tring out Elasticsearch",
      "term" : {
        "field" : "message"
      }
    },
    "my-suggest-2" : {
      "text" : "kmichy",
      "term" : {
        "field" : "user"
      }
    }
  }
}

示例 3:多个建议查询可以使用全局的查询文本

POST _search
{
  "suggest": {
    "text" : "tring out Elasticsearch",
    "my-suggest-1" : {
      "term" : {
        "field" : "message"
      }
    },
    "my-suggest-2" : {
       "term" : {
        "field" : "user"
       }
    }
  }
}

二、准备数据

准备一个叫做blogs的索引,配置一个text字段。

PUT /blogs/
{
  "mappings": {
    "properties": {
      "body": {
        "type": "text"
      }
    }
  }
}

通过bulk api写入几条文档

POST _bulk/?refresh=true
{"index":{"_index":"blogs"}}
{"body":"Lucene is cool"}
{"index":{"_index":"blogs"}}
{"body":"Elasticsearch builds on top of lucene"}
{"index":{"_index":"blogs"}}
{"body":"Elasticsearch rocks"}
{"index":{"_index":"blogs"}}
{"body":"Elastic is the company behind ELK stack"}
{"index":{"_index":"blogs"}}
{"body":"elk rocks"}
{"index":{"_index":"blogs"}}
{"body":"elasticsearch is rock solid"}

此时blogs索引里已经有一些文档了,可以进行下一步的探索。为帮助理解,我们先看看哪些term会存在于词典里。
将输入的文本分析一下:

POST _analyze
{
  "text": [
    "Lucene is cool",
    "Elasticsearch builds on top of lucene",
    "Elasticsearch rocks",
    "Elastic is the company behind ELK stack",
    "elk rocks",
    "elasticsearch is rock solid"
  ]
}

这些分出来的token都会成为词典里一个term,注意有些token会出现多次,因此在倒排索引里记录的词频会比较高,同时记录的还有这些token在原文档里的偏移量和相对位置信息。

三、Suggester 介绍

  • Term Suggester: 对给入的文本进行分词,为每个词进行模糊查询提供词项建议,并不会考虑多个term/词组之间的关系。。API调用方只需为每个token挑选options里的词,组合在一起返回给用户前端即可
  • Phrase Suggester,在Term Suggester的基础上,会考量多个term之间的关系,比如是否同时出现在索引的原文里,相邻程度,以及词频等等
  • Completion Suggester,FST数据结构,类似Trie树,不用打开倒排,快速返回,前缀匹配
  • Context Suggester,在Completion Suggester的基础上,用于filter和boost

1. Term suggester

term 词项建议器,对给入的文本进行分词,为每个词进行模糊查询提供词项建议。对于在索引中存在词默认不提供建议词,不存在的词则根据模糊查询结果进行排序后取一定数量的建议词。

常用的建议选项:

text搜索文本。建议文本是必填选项,需要全局或按建议设置。
field从中获取候选建议的字段。这是必需选项,需要全局设置或根据建议设置。
analyzer分析器用来分析建议文本。默认为建议字段的搜索分析器。
size每个建议文本将返回的最大数。
sort定义每个建议文本术语应如何分类建议。两个可能的值:score:首先按分数排序,然后记录频次,然后是词条本身。frequency:首先按文档频率排序,然后按相似性得分排序,然后再按术语本身排序。
suggest_mode提示模式控制要包含的建议,或控制建议的文本术语和建议的控件。可以指定三个可能的值:missing:仅对未在索引中的建议文本术语提供建议。这是默认值。popular:仅建议在比原始建议文本术语更多的文档中出现的建议。always:根据建议文本中的术语建议任何匹配的建议。
lowercase_terms在文本分析之后,将建议的文本术语小写。
max_edits最大编辑距离候选建议可以具有以便被认为是建议。只能是 1 到 2 之间的值。任何其他值都将导致引发错误的请求错误。默认为 2。
prefix_length必须匹配的最小前缀字符数才能成为建议的候选者。默认值为 1。增加此数字可提高拼写检查性能。通常,拼写错误不会出现在学期开始时。(旧名称 “prefix_len” 已弃用)

示例 1:

POST twitter/_search
{
  "suggest" : { <!-- 定义建议查询 -->
    "my-suggestion" : { <!-- 一个建议查询名 -->
      "text" : "lucne rock", <!-- 查询文本 -->
      "term" : { <!-- 使用词项建议器 -->
        "suggest_mode": "missing",
        "field" : "body" <!-- 指定在哪个字段上获取建议词 -->
      }
    }
  }
}

返回结果

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "suggest" : {
    "my-suggestion" : [
      {
        "text" : "lucne",
        "offset" : 0,
        "length" : 5,
        "options" : [
          {
            "text" : "lucene",
            "score" : 0.8,
            "freq" : 2
          }
        ]
      },
      {
        "text" : "rock",
        "offset" : 6,
        "length" : 4,
        "options" : [ ]
      }
    ]
  }
}

在返回结果里"suggest" -> “my-suggestion"部分包含了一个数组,每个数组项对应从输入文本分解出来的token(存放在"text"这个key里)以及为该token提供的建议词项(存放在options数组里)。 示例里返回了"lucne”,"rock"这2个词的建议项(options),其中"rock"的options是空的,表示没有可以建议的选项,为什么? 上面提到了,我们为查询提供的suggest mode是"missing",由于"rock"在索引的词典里已经存在了,够精准,就不建议啦。 只有词典里找不到词,才会为其提供相似的选项。

如果将"suggest_mode"换成"popular"会是什么效果?

尝试一下,重新执行查询,返回结果里"rock"这个词的option不再是空的,而是建议为rocks。

  "suggest" : {
    "my-suggestion" : [
      {
        "text" : "lucne",
        "offset" : 0,
        "length" : 5,
        "options" : [
          {
            "text" : "lucene",
            "score" : 0.8,
            "freq" : 2
          }
        ]
      },
      {
        "text" : "rock",
        "offset" : 6,
        "length" : 4,
        "options" : [
          {
            "text" : "rocks",
            "score" : 0.75,
            "freq" : 2
          }
        ]
      }
    ]
  }

回想一下,rock和rocks在索引词典里都是有的。 不难看出即使用户输入的token在索引的词典里已经有了,但是因为存在一个词频更高的相似项,这个相似项可能是更合适的,就被挑选到options里了。 最后还有一个"always" mode,其含义是不管token是否存在于索引词典里都要给出相似项。

Term suggester正如其名,只基于analyze过的单个term去提供建议,并不会考虑多个term之间的关系。API调用方只需为每个token挑选options里的词,组合在一起返回给用户前端即可。 那么有无更直接办法,API直接给出和用户输入文本相似的内容? 答案是有,这就要求助Phrase Suggester了。

2. phrase suggester

phrase 短语建议,在 term 的基础上,会考量多个 term 之间的关系,比如是否同时出现在索引的原文里,相邻程度,以及词频等

看个范例就比较容易明白了:

POST /blogs/_search
{
  "suggest": {
    "my-suggestion": {
      "text": "lucne and elasticsear rock",
      "phrase": {
        "field": "body",
        "highlight": {
          "pre_tag": "<em>",
          "post_tag": "</em>"
        }
      }
    }
  }
}

返回结果:

 "suggest" : {
    "my-suggestion" : [
      {
        "text" : "lucne and elasticsear rock",
        "offset" : 0,
        "length" : 26,
        "options" : [
          {
            "text" : "lucene and elasticsearch rock",
            "highlighted" : "<em>lucene</em> and <em>elasticsearch</em> rock",
            "score" : 0.004993905
          },
          {
            "text" : "lucne and elasticsearch rock",
            "highlighted" : "lucne and <em>elasticsearch</em> rock",
            "score" : 0.0033391973
          },
          {
            "text" : "lucene and elasticsear rock",
            "highlighted" : "<em>lucene</em> and elasticsear rock",
            "score" : 0.0029183894
          }
        ]
      }
    ]
  }

options直接返回一个phrase列表,由于加了highlight选项,被替换的term会被高亮。因为lucene和elasticsearch曾经在同一条原文里出现过,同时替换2个term的可信度更高,所以打分较高,排在第一位返回。Phrase suggester有相当多的参数用于控制匹配的模糊程度,需要根据实际应用情况去挑选和调试。

3. Completion suggester 自动补全

针对自动补全(“Auto Completion”)场景而设计的建议器。此场景下用户每输入一个字符的时候,就需要即时发送一次查询请求到后端查找匹配项,在用户输入速度较高的情况下对后端响应速度要求比较苛刻。因此实现上它和前面两个 Suggester 采用了不同的数据结构,索引并非通过倒排来完成,而是将 analyze 过的数据编码成 FST 和索引一起存放。对于一个 open 状态的索引,FST 会被 ES 整个装载到内存里的,进行前缀查找速度极快。 但是 FST 只能用于前缀查找,这也是 Completion Suggester 的局限所在。

官网链接:

https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html

  • completion:es 的一种特有类型,专门为 suggest 提供,基于内存,性能很高。

  • prefix query:基于前缀查询的搜索提示,是最常用的一种搜索推荐查询。

    • prefix:客户端搜索词
    • field:建议词字段
    • size:需要返回的建议词数量(默认 5)
    • skip_duplicates:是否过滤掉重复建议,默认 false
  • fuzzy query

    • fuzziness:允许的偏移量,默认 auto
    • transpositions:如果设置为 true,则换位计为一次更改而不是两次更改,默认为 true。
    • min_length:返回模糊建议之前的最小输入长度,默认 3
    • prefix_length:输入的最小长度(不检查模糊替代项)默认为 1
    • unicode_aware:如果为 true,则所有度量(如模糊编辑距离,换位和长度)均以 Unicode 代码点而不是以字节为单位。这比原始字节略慢,因此默认情况下将其设置为 false。
  • regex query:可以用正则表示前缀,不建议使用

为了使用自动补全,索引中用来提供补全建议的字段需特殊设计,字段类型为 completion。

PUT /blogs_completion/
{
  "mappings": {
    "properties": {
      "body": {
        "type": "completion"
      }
    }
  }
}

用bulk API索引点数据:

POST _bulk/?refresh=true
{"index":{"_index":"blogs_completion"}}
{"body":"Lucene is cool"}
{"index":{"_index":"blogs_completion"}}
{"body":"Elasticsearch builds on top of lucene"}
{"index":{"_index":"blogs_completion"}}
{"body":"Elasticsearch rocks"}
{"index":{"_index":"blogs_completion"}}
{"body":"Elastic is the company behind ELK stack"}
{"index":{"_index":"blogs_completion"}}
{"body":"the elk stack rocks"}
{"index":{"_index":"blogs_completion"}}
{"body":"elasticsearch is rock solid"}

查找:

POST blogs_completion/_search?pretty
{
  "size": 0,
  "suggest": {
    "blog-suggest": {
      "prefix": "elastic i",
      "completion": {
        "field": "body"
      }
    }
  }
}

结果:

  "suggest" : {
    "blog-suggest" : [
      {
        "text" : "elastic i",
        "offset" : 0,
        "length" : 9,
        "options" : [
          {
            "text" : "Elastic is the company behind ELK stack",
            "_index" : "blogs_completion",
            "_type" : "_doc",
            "_id" : "8nI0YYwBPMQ17EXsspBh",
            "_score" : 1.0,
            "_source" : {
              "body" : "Elastic is the company behind ELK stack"
            }
          }
        ]
      }
    ]
  }

值得注意的一点是Completion Suggester在索引原始数据的时候也要经过analyze阶段,取决于选用的analyzer不同,某些词可能会被转换,某些词可能被去除,这些会影响FST编码结果,也会影响查找匹配的效果。

比如我们删除上面的索引,重新设置索引的mapping,将analyzer更改为"english":

DELETE blogs_completion
PUT /blogs_completion/
{
  "mappings": {
    "properties": {
      "body": {
        "type": "completion",
        "analyzer": "english"
      }
    }
  }
}

bulk api索引同样的数据后,执行下面的查询:

POST blogs_completion/_search?pretty
{
  "size": 0,
  "suggest": {
    "blog-suggest": {
      "prefix": "elastic i",
      "completion": {
        "field": "body"
      }
    }
  }
}

居然没有匹配结果了,多么费解! 原来我们用的english analyzer会剥离掉stop word,而is就是其中一个,被剥离掉了!
用analyze api测试一下:

POST _analyze
{
  "analyzer": "english",
  "text": "elasticsearch is rock solid"
}

会发现只有3个token:

{
  "tokens" : [
    {
      "token" : "elasticsearch",
      "start_offset" : 0,
      "end_offset" : 13,
      "type" : "<ALPHANUM>",
      "position" : 0
    },
    {
      "token" : "rock",
      "start_offset" : 17,
      "end_offset" : 21,
      "type" : "<ALPHANUM>",
      "position" : 2
    },
    {
      "token" : "solid",
      "start_offset" : 22,
      "end_offset" : 27,
      "type" : "<ALPHANUM>",
      "position" : 3
    }
  ]
}

FST只编码了这3个token,并且默认的还会记录他们在文档中的位置和分隔符。 用户输入"elastic i"进行查找的时候,输入被分解成"elastic"和"i",FST没有编码这个“i” , 匹配失败。

好吧,如果你现在还足够清醒的话,试一下搜索"elastic is",会发现又有结果,why? 因为这次输入的text经过english analyzer的时候is也被剥离了,只需在FST里查询"elastic"这个前缀,自然就可以匹配到了。

其他能影响completion suggester结果的,还有诸如"preserve_separators","preserve_position_increments"等等mapping参数来控制匹配的模糊程度。以及搜索时可以选用Fuzzy Queries,使得上面例子里的"elastic i"在使用english analyzer的情况下依然可以匹配到结果。

因此用好Completion Sugester并不是一件容易的事,实际应用开发过程中,需要根据数据特性和业务需要,灵活搭配analyzer和mapping参数,反复调试才可能获得理想的补全效果。

回到篇首百度搜索框的补全/纠错功能,如果用ES怎么实现呢?我能想到的一个的实现方式:

  1. 在用户刚开始输入的过程中,使用Completion Suggester进行关键词前缀匹配,刚开始匹配项会比较多,随着用户输入字符增多,匹配项越来越少。如果用户输入比较精准,可能Completion Suggester的结果已经够好,用户已经可以看到理想的备选项了。
  2. 如果Completion Suggester已经到了零匹配,那么可以猜测是否用户有输入错误,这时候可以尝试一下Phrase Suggester。
  3. 如果Phrase Suggester没有找到任何option,开始尝试term Suggester。

精准程度上(Precision)看: Completion > Phrase > term, 而召回率上(Recall)则反之。从性能上看,Completion Suggester是最快的,如果能满足业务需求,只用Completion Suggester做前缀匹配是最理想的。 Phrase和Term由于是做倒排索引的搜索,相比较而言性能应该要低不少,应尽量控制suggester用到的索引的数据量,最理想的状况是经过一定时间预热后,索引可以全量map到内存。

4. context suggester

完成建议者会考虑索引中的所有文档,但是通常来说,我们在进行智能推荐的时候最好通过某些条件过滤,并且有可能会针对某些特性提升权重。

  • contexts:上下文对象,可以定义多个

    • name:context的名字,用于区分同一个索引中不同的context对象。需要在查询的时候指定当前name

    • type:context对象的类型,目前支持两种:category和geo,分别用于对suggest item分类和指定地理位置。

    • boost:权重值,用于提升排名

  • path:如果没有path,相当于在PUT数据的时候需要指定context.name字段,如果在Mapping中指定了path,在PUT数据的时候就不需要了,因为 Mapping是一次性的,而PUT数据是频繁操作,这样就简化了代码。这段解释有木有很牛逼,网上搜到的都是官方文档的翻译,觉悟雷同。

# context suggester
# 定义一个名为 place_type 的类别上下文,其中类别必须与建议一起发送。
# 定义一个名为 location 的地理上下文,类别必须与建议一起发送
DELETE place
PUT place
{
  "mappings": {
    "properties": {
      "suggest": {
        "type": "completion",
        "contexts": [
          {
            "name": "place_type",
            "type": "category"
          },
          {
            "name": "location",
            "type": "geo",
            "precision": 4
          }
        ]
      }
    }
  }
}

PUT place/_doc/1
{
  "suggest": {
    "input": [ "timmy's", "starbucks", "dunkin donuts" ],
    "contexts": {
      "place_type": [ "cafe", "food" ]                    
    }
  }
}
PUT place/_doc/2
{
  "suggest": {
    "input": [ "monkey", "timmy's", "Lamborghini" ],
    "contexts": {
      "place_type": [ "money"]                    
    }
  }
}


GET place/_search
POST place/_search?pretty
{
  "suggest": {
    "place_suggestion": {
      "prefix": "sta",
      "completion": {
        "field": "suggest",
        "size": 10,
        "contexts": {
          "place_type": [ "cafe", "restaurants" ]
        }
      }
    }
  }
}
# 某些类别的建议可以比其他类别提升得更高。以下按类别过滤建议,并额外提升与某些类别相关的建议
GET place/_search
POST place/_search?pretty
{
  "suggest": {
    "place_suggestion": {
      "prefix": "tim",
      "completion": {
        "field": "suggest",
        "contexts": {
          "place_type": [                             
            { "context": "cafe" },
            { "context": "money", "boost": 2 }
          ]
        }
      }
    }
  }
}

# 地理位置筛选器
PUT place/_doc/3
{
  "suggest": {
    "input": "timmy's",
    "contexts": {
      "location": [
        {
          "lat": 43.6624803,
          "lon": -79.3863353
        },
        {
          "lat": 43.6624718,
          "lon": -79.3873227
        }
      ]
    }
  }
}
POST place/_search
{
  "suggest": {
    "place_suggestion": {
      "prefix": "tim",
      "completion": {
        "field": "suggest",
        "contexts": {
          "location": {
            "lat": 43.662,
            "lon": -79.380
          }
        }
      }
    }
  }
}



# 定义一个名为 place_type 的类别上下文,其中类别是从 cat 字段中读取的。
# 定义一个名为 location 的地理上下文,其中的类别是从 loc 字段中读取的
DELETE place_path_category
PUT place_path_category
{
  "mappings": {
    "properties": {
      "suggest": {
        "type": "completion",
        "contexts": [
          {
            "name": "place_type",
            "type": "category",
            "path": "cat"
          },
          {
            "name": "location",
            "type": "geo",
            "precision": 4,
            "path": "loc"
          }
        ]
      },
      "loc": {
        "type": "geo_point"
      }
    }
  }
}
# 如果映射有路径,那么以下索引请求就足以添加类别
# 这些建议将与咖啡馆和食品类别相关联
# 如果上下文映射引用另一个字段并且类别被明确索引,则建议将使用两组类别进行索引
PUT place_path_category/_doc/1
{
  "suggest": ["timmy's", "starbucks", "dunkin donuts"],
  "cat": ["cafe", "food"] 
}
POST place_path_category/_search?pretty
{
  "suggest": {
    "place_suggestion": {
      "prefix": "tim",
      "completion": {
        "field": "suggest",
        "contexts": {
          "place_type": [                             
            { "context": "cafe" }
          ]
        }
      }
    }
  }
}

参考

官网

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

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

相关文章

Mybatis插件入门

专栏精选 引入Mybatis Mybatis的快速入门 Mybatis的增删改查扩展功能说明 mapper映射的参数和结果 Mybatis复杂类型的结果映射 Mybatis基于注解的结果映射 Mybatis枚举类型处理和类型处理器 再谈动态SQL Mybatis配置入门 Mybatis行为配置之Ⅰ—缓存 Mybatis行为配置…

【经典算法】有趣的算法之---蚁群算法梳理

every blog every motto: You can do more than you think. 0. 前言 蚁群算法记录 1. 简介 蚁群算法(Ant Clony Optimization, ACO)是一种群智能算法,它是由一群无智能或有轻微智能的个体(Agent)通过相互协作而表现出智能行为,从而为求解复杂问题提供了一个新的可能性…

JDK9及之后版本使用 jlink 生成定制化的 JRE

许多java软件的运行需要依赖jre&#xff0c;在 jdk8 之后&#xff0c;不再提供默认的 jre&#xff0c;后续如果项目中还是想用 jre 的形式发布软件&#xff0c;那么可以使用 jlink 工具生成 jre。 一、jlink 命令详解 jlink 二、查看jdk中包含的所有模块 如果在 jdk 安装文件夹…

css 用多个阴影做出光斑投影的效果 box-shadow

css 用多个阴影做出光斑投影的效果 box-shadow 你首先需要知道的一点是 box-shadow 可以接收多个值&#xff0c;也就是可以设置多个阴影&#xff0c;这样就可以做一个类似光斑投影的效果。 一、效果 二、代码 里面用到了我一些 scss 工具方法&#xff0c;不过不影响&#xf…

Android MVP 写法

前言 Model&#xff1a;负责数据逻辑 View&#xff1a;负责视图逻辑 Presenter&#xff1a;负责业务逻辑 持有关系&#xff1a; 1、View 持有 Presenter 2、Model 持有 Presenter 3、Presenter 持有 View 4、Presenter 持有 Model 辅助工具&#xff1a;ViewBinding 执行…

【华为机试】2023年真题B卷(python)-观看文艺汇演-计算演出场次

一、题目 题目描述&#xff1a; 一个人只能同时观看一场演出&#xff0c;且不能迟到早退&#xff0c;由于演出分布在不同的演出场地&#xff0c;所以连续观看的演出最少有15分钟的时间间隔&#xff0c;小明是一个狂热的文艺迷&#xff0c;想观看尽可能多的演出&#xff0c; 现给…

【并发设计模式】聊聊线程本地存储模式如何实现的线程安全

前面两篇文章&#xff0c;通过两阶段终止的模式进行优雅关闭线程&#xff0c;利用数据不变性的方式保证数据安全&#xff0c;以及基于COW的模式&#xff0c;保证读数据的安全。本篇我们来简述下如果利用线程本地存储的方式保证线程安全。 首先一个大前提就是并发问题&#xff…

八皇后问题(C语言)

了解题意 在一个8x8的棋盘上放置8个皇后&#xff0c;使得任何两个皇后都不能处于同一行、同一列或同一斜线上。问有多少种方法可以放置这8个皇后&#xff1f; 解决这个问题的目标是找到所有符合要求的皇后摆放方式&#xff0c;通常使用回溯算法来求解。回溯算法会尝试所有可能…

[蓝桥杯2022省赛] X 图形

X 图形 问题描述 给定一个字母矩阵。一个 X 图形由中心点和由中心点向四个 4545 度斜线方向引出的直线段组成&#xff0c;四条线段的长度相同&#xff0c;而且四条线段上的字母和中心点的字母相同。 一个 X 图形可以使用三个整数r,c,L 来描述&#xff0c;其中 r,c 表示中心点…

PiflowX组件-ReadFromKafka

ReadFromKafka组件 组件说明 从kafka中读取数据。 计算引擎 flink 有界性 Unbounded 组件分组 kafka 端口 Inport&#xff1a;默认端口 outport&#xff1a;默认端口 组件属性 名称展示名称默认值允许值是否必填描述例子kafka_hostKAFKA_HOST“”无是逗号分隔的Ka…

腾讯云标准型S5服务器4核8G配置优惠价格表

腾讯云4核8G服务器S5和轻量应用服务器优惠价格表&#xff0c;轻量应用服务器和CVM云服务器均有活动&#xff0c;云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元&#xff0c;5年6490.44元&#xff0c;轻量应用服务器4核8G12M带宽一年446元、529元15个月&#xff0c;腾讯云…

malloc、calloc、realloc、free函数的使用及注意事项

malloc函数 malloc函数的返回值为void*类型 内存管理函数操作的内存是在堆区空间 malloc函数使用示例 free(p)相当于值传递&#xff0c;不能改变p本身。 free只是释放了空间&#xff0c;释放后p依然指向原地址&#xff0c;故需要手动置NULL。 calloc函数 calloc可以指定开辟n个…

【Week-P3】CNN天气识别

文章目录 一、环境配置二、准备数据三、搭建网络结构四、开始训练五、查看训练结果六、总结6.1 不改变学习率的前提下&#xff0c;将训练epoch分别增加到50、60、70、80、90&#xff08;1&#xff09;epoch 50 的训练情况如下&#xff1a;&#xff08;2&#xff09;epoch 60 …

UE4运用C++和框架开发坦克大战教程笔记(十二)(第37~39集)

UE4运用C和框架开发坦克大战教程笔记&#xff08;十二&#xff09;&#xff08;第37~39集&#xff09; 37. 延时事件系统38. 协程逻辑优化更新39. 普通按键绑定 37. 延时事件系统 由于梁迪老师是写 Unity 游戏出身的&#xff0c;所以即便 UE4 有自带的 TimeManager 这样的延时…

直方图与均衡化

直方图 统计图像中相同像素点的数量。 使用cv2.calcHist(images, channels, mask, histSize, ranges)函数 images&#xff1a;原图像图像格式为uint8或float32&#xff0c;当传入函数时应用[]括起来&#xff0c;例如[img]。 channels&#xff1a;同样用中括号括起来&#xff…

pytest pytest-html优化样式

conftest.py import pytest from pytest_metadata.plugin import metadata_keydef pytest_html_report_title(report):report.title"接口测试报告"def pytest_configure(config):# 获取命令行参数中的测试环境、测试版本、开始时间、测试人员config.stash[metadata_…

鸿蒙Harmony(七)ArkUI--循环foreachList组件自定义组件

循环foreach import Prompt from system.promptclass Item {icon: Resourcename: stringprice: numberconstructor(icon: Resource, name: string, price: number) {this.icon iconthis.name namethis.price price} }Entry Component struct Index {State message: string …

Linux 安装Jupyter notebook 并开启远程访问

文章目录 安装Python安装pip安装Jupyter启动Jupyter Notebook1. 生成配置文件2. 创建密码3. 修改jupyter notebook的配置文件4. 启动jupyter notebook5. 远程访问jupyter notebook 安装Python 确保你的系统上已经安装了Python。大多数Linux发行版都预装了Python。你可以在终端…

flutter 之proto

和嵌入式用proto协议来通信&#xff0c;以mac来演示 先在电脑上安装protobuf&#xff08;在博主文章内容里面搜Mac安装protobuf&#xff09;&#xff0c;然后在桌面上放这几个文件&#xff0c;且build_proto_dart.sh文件内容如图所示 #!/bin/bashSCRIPT$(readlink -f "$0…

NFC物联网智能学生宿舍系统设计方案

随着物联网技术的不断发展&#xff0c;智慧城市、智能家居、智慧校园的建设也在如火如茶地进行。本文结合物联网发展过程中相关的技术&#xff0c;应用到智慧校园的建设过程中&#xff0c;将学生宿舍打造成舒适、安全的集体空间&#xff0c;该系统可以对学生宿舍实现智能开门、…