原文:Elasticsearch入门教程(三):Elasticsearch索引&映射

版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。

索引概念简介

通常说的索引有两种词性,名称和动词。

  • 动词索引indexing,索引一个文档,表示把一个文档存储到索引Index里,可以用来查询和检索,es采用倒排索引
  • 名词索引index,简单的理解成关系型数据库中的数据库的概念

索引的命名必须是全部小写,不能以下划线开头.

创建索引

创建索引可以显式创建,也可以隐式创建。

  • 显式创建:在关系型数据库中,需要先建数据库,在创建数据库时可以指定一些配置,如字符编码,数据库引擎等,创建表时需要指定表都包含哪些列,每个列的数据类型等,在在Elasticsearch中创建数据库(索引)和创建表(映射)是一步完成的,显式创建需要在创建时指定对索引的一些配置,需要列举出索引包含的字段,也就是所谓的映射Mapping
  • 隐式操作:隐式操作的方式是直接向索引中插入一条文档即可,es在插入的时候会判断索引是否存在,如果不存在,系统会根据文档包含的字段作为索引的映射,对索引的一些配置采用默认的配置来创建出来索引,创建索引的过程是es在后台默默的实现的。

显式创建可以根据具体情况对索引进行配置,而且对于中文分词es是默认采用的分词是适合英文并适合中文的,可以在创建索引的时候自己指定分词器。

ES支持的数据类型

  • text 文本类型,text类型如果不显示指定映射的字段属性,默认是使用标准分词器进行分词,一般数据类型是text要么显示指定分词器,要么不分词,一般不使用默认的分词器(除非文本是纯英文)
  • keyword : 如果数组中的值是字符串,最好使用keyword, 它不会对字符串进行分词
  • date 支持的格式有:可以通过format定义日期的数据格式,也支持毫秒数
  • boolean
  • float
  • double
  • byte
  • short
  • integer
  • long
  • object
  • nested : 嵌套对象, 用于数组中的元素是对象的[{}, {}]
  • ip 即支持ipv4也支持ipv6
  • completion
  • binary
  • geo-point: 支持经纬度存储和距离范围检索
  • geo-shape:支持任意图形范围的检索,例如矩形和平面多边形

注意:不同的数据类型索引的方式有稍许不同,如date何text类型不一样,date采用精确匹配,text采用全文检索方式。对于数组,es并没有专门的数组类型。任何域都可以包含0、1或者多个值,就像全文域分析得到多个词条。这暗示 数组中所有的值必须是相同数据类型的。

映射mappings

映射就是创建索引时指定都包含哪些字段以及字段的数据类型、分词器等一些设置。

字段设置参数

  • “type”: “text”, // 指定字段的数据类型
  • “analyzer”:”ik _max_word”, //指定分词器的名称,即可用使用内置的分词器也可以使用第三方分词器
    • 默认standard,
    • 内置的分析器有whitespace 、 simple和english
    • 第三方分词器:ik分词器 包括ik_max_word和ik_smart,ik_max_word:会将文本做最细粒度的拆分;尽可能多的拆分出词语 ,ik_smart:会做最粗粒度的拆分;已被分出的词语将不会再次被其它词语占有
  • “search_analyzer”:”ik _max_word” // 指定查询的分词器,默认和analyzer保持一致,一般分词器和查询分词器要保持一致
  • “properties”: {}, // 当数据类型是object时,需要具体指定内部对象对应的字段
  • “format”: “yyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis” // 格式化,一般用于指定日期类型的格式
  • “dynamic”: “strict” 动态映射配置,当文档中发现新字段时应该如何处理, 可以用在根 object 或任何 object 类型的字段上,你可以将 dynamic 的默认值设置为 strict , 而只在指定的内部对象中开启它
    • true: 默认值,动态添加新的字段
    • false: 忽略新的字段
    • strict: 如果遇到新字段抛出异常,如果Elasticsearch是作为重要的数据存储,可能就会期望遇到新字段就会抛出异常,这样能及时发现问题。
  • dynamic_templates 动态模板:为满足条件的字段做统一映射,可以通过字段名称或者字段类型来匹配指定的映射规则,每个模板都有一个名称,你可以用来描述这个模板的用途, 一个mapping来指定映射应该怎样使用,以及至少一个参数 (如 match) 来定义这个模板适用于哪个字段。

    模板按照顺序来检测;第一个匹配的模板会被启用

    • match 参数只匹配字段名称
    • match_mapping_type 允许你应用模板到特定类型的字段上,就像有标准动态映射规则检测的一样
  • “fielddata”:boolean //针对分词字段,参与排序或聚合时能提高性能,默认是false,false是不允许聚合操作的
  • “boost”:1.23 // 权重:字段级别的分数加权,指定字段在搜索时所占的权重,所占的百分比
  • “fields”:{“raw”:{“type”:”keyword”}} //可以对一个字段提供多种索引模式,同一个字段的值,一个分词,一个不分词,应用场景:即可以用于对字符串进行字符排序,也可以全文索引,排序时使用字段.raw来引用排序字段
  • “index”: “analyzed”, // 指定文本类型的字段是否分词、是否存储该字段的值(在新版本中index值为boolean类型,语意也发生了变化,TODO待更新),有三个值:
    • analyzed:首先分析字符串,然后索引(存储)它。换句话说,以全文索引这个域(也就是说即分词,又存储字段的值,即可以通过全文检索的方式对该字段进行搜索)
    • not_analyzed:索引(存储)这个域,所以它能够被搜索,但索引的是精确值。不会对它进行分析(不对字段的值进行分词,而是完整的存储该值,所以只能通过精确值才能搜索出来,即完全匹配,相当于sql中的等号=的作用)
    • no:不索引这个域。这个域不会被搜索到(对该字段不分词,也不存储,相当于没有这个字段一样???)
  • “store”:false//是否单独设置此字段的是否存储而从_source字段中分离,默认是false,只能搜索,不能获取值
  • “doc_values”:false//对not_analyzed字段,默认都是开启,分词字段不能使用,对排序和聚合能提升较大性能,节约内存
  • “ignore_above”:100 //超过100个字符的文本,将会被忽略,不被索引
  • “include_in_all”:ture//设置是否此字段包含在_all字段中,默认是true,除非index设置成no选项
  • “index_options”:”docs”//4个可选参数docs(索引文档号) ,freqs(文档号+词频),positions(文档号+词频+位置,通常用来距离查询),offsets(文档号+词频+位置+偏移量,通常被使用在高亮字段)分词字段默认是position,其他的默认是docs
  • “norms”:{“enable”:true,”loading”:”lazy”}//分词字段默认配置,不分词字段:默认{“enable”:false},存储长度因子和索引时boost,建议对需要参与评分字段使用 ,会额外增加内存消耗量
  • “null_value”:”NULL”//设置一些缺失字段的初始化值,只有string可以使用,分词字段的null值也会被分词
  • “position_increament_gap”:0//影响距离查询或近似查询,可以设置在多值字段的数据上火分词字段上,查询时可指定slop间隔,默认值是100
  • “similarity”:”BM25”//默认是TF/IDF算法,指定一个字段评分策略,仅仅对字符串型和分词类型有效
  • “term_vector”:”no”//默认不存储向量信息,支持参数yes(term存储),with_positions(term+位置),with_offsets(term+偏移量),with_positions_offsets(term+位置+偏移量) 对快速高亮fast vector highlighter能提升性能,但开启又会加大索引体积,不适合大数据量用

ik分词器 https://github.com/medcl/elasticsearch-analysis-ik 支持自定义热词配置(如 香菇 蓝瘦 帅的一逼 等)

// 默认standard,内置的分析器有whitespace 、 simple 和 english
// ik支持两种分词器:ik_max_word,ik_smart
// 分析器:用于测试分词的数据
GET /_analyze
{
"analyzer" : "ik_max_word",
"text": "美国留给伊拉克的是个烂摊子吗"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

settings设置

settings用于设置索引的分片数量、副本数量、默认的分词器等,Elasticsearch 提供了优化好的默认配置。 除非你理解这些配置的作用并且知道为什么要去修改,否则不要随意修改。

  • “number_of_shards” : 5, // 每个索引的主分片数,默认值是 5 。这个配置在索引创建后不能修改。
  • “number_of_replicas” : 1, // 每个主分片的副本数,默认值是 1 。对于活动的索引库,这个配置可以随时修改。
  • “analysis” : { “analyzer” : { “ik” : { “tokenizer” : “ik_ max_word” } } }
// 创建只有 一个主分片,没有副本的小索引:
PUT /my_temp_index
{
"settings": {
"number_of_shards" : 1,
"number_of_replicas" : 0
}
}
// 用update-index-settings API 动态修改副本数:
PUT /my_temp_index/_settings
{
"number_of_replicas": 1
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

aliases别名

索引别名就像一个快捷方式或软连接,或者是一个指向,都是最终指的同一个东西,别名 带给我们极大的灵活性,允许我们做下面这些:

  • 在运行的集群中可以无缝的从一个索引切换到另一个索引
  • 给多个索引分组 (例如, last_three_months)
  • 给索引的一个子集创建 视图

有两种方式管理别名: _alias用于单个操作, _aliases用于执行多个原子级操作。

Mapping一旦创建是不允许修改字段的数据类型的,为了防止以后有可能修改索引的情况,刚开始创建索引时最好就为该索引创建一个别名,然后在程序中直接使用别名,而不使用真实的索引名称。

如果后面需要要修改映射,可以再创建一个新的索引,然后把之前索引里的数据导入到新创建的索引里, 为新索引增加一个别名,将别名从老索引中移除,这样应用程序仍然使用的是别名,而这个别名已经指向了新的索引,这样就达到了不修改索引名而修改索引的目的。

// 0. 创建索引(age的类型为long)
PUT /school_v1
{
"mappings": {
"students": {
"properties": {
"name": { "type": "text" },
"age": {"type": "long"}
}
}
}
} // 1. 为索引创建一个别名
PUT /school_v1/_alias/school // 查看别名指向的索引
GET /*/_alias/school
// 查询索引对应的别名
GET /school_v1/_alias/* // 2.创建一个新的索引,名字不能和之前的不一样,这次将age的数据类型改为short
PUT /school_v2
{
"mappings": {
"students": {
"properties": {
"name": { "type": "text" },
"age": {"type": "short"}
}
}
}
} // 3.迁移数据:将之前的索引里的文档迁移到新的索引上
// 先将数据批量查询出来,然后批量插入
GET /school/students/_search?scroll=1m POST /schools/students/_bulk
{"index": {"_id": 1}}
{"name": "张三","age": 27}
{"index": {"_id": 2}}
{"name": "小明","age": 28} GET /schools/students/_search // 4.为新索引增加别名,别名名称为老索引名称,这样系统可以直接使用老索引的名称来操作新索引
POST /_aliases
{
"actions": [
{
"add": { "index": "school_v2", "alias": "school"},
"remove": { "index": "school_v1", "alias": "school"}
}
]
} GET /school/students/_search
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

别名就是索引的另一个名字,就像人的姓名和笔名一样,都是指向的同一个人,可以通过POST /_aliases 路径对别名进行add、remove操作

TIP: 在你的应用中使用别名而不是索引名。然后你就可以在任何时候重建索引。别名的开销很小,应该广泛使用。

索引操作

创建索引

PUT /{index}

// 注意:当前创建的索引的动态映射配置根对象是不允许添加新字段的,动态映射类型为严格类型,但是内部对象是允许添加新字段的
PUT /shop_v1
{
"aliases": {
"shop": {}
},
"settings" : {
"number_of_shards" : 5,
"number_of_replicas" : 1,
"refresh_interval": "1s",
"analysis" : {
"analyzer" : {
"ik" : {
"tokenizer" : "ik_max_word"
}
}
}
},
"mappings": {
"goods": {
"dynamic": "strict",
"dynamic_templates":[
{ "date": {
"match": "*_date",
"match_mapping_type": "date",
"mapping": {
"type": "date",
"format": "yyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}},
{ "ik": {
"match": "*",
"match_mapping_type": "string",
"mapping": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
}
}}
],
"properties": {
"name": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
},
"price": {
"type": "double"
},
"quantity": {
"type": "integer"
},
"colors": {
"type": "keyword"
},
"is_discount": {
"type": "boolean"
},
"create_date": {
"type": "date",
"format": "yyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"ip_addr": {
"type": "ip"
},
"location": {
"type": "geo_point",
"lat_lon": true
},
"merchant": {
"type": "object",
"dynamic": true,
"properties": {
"id": { "type": "long" },
"shop_name": { "type": "text" }
}
},
"cpu": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90

refresh_interval:索引刷新时间间隔,一个持续时间值, 例如 1s(1 秒) 或 2m(2 分钟)。 一个绝对值1表示的是1毫秒 –无疑会使你的集群陷入瘫痪, -1:表示关闭刷新, 默认为一秒,如果索引了一个文档然后立即尝试搜索它,但却没有搜到,可能是还没有到间隔时间,还没有刷新

  • 查看所有索引 GET /_cat/indices?v&pretty

  • 查看某个索引 GET /{index}

  • 删除索引单个索引 DELETE /{index}

  • 删除所有索引 DELETE /_all 或者 DELETE /*

  • 删除多个索引: DELETE /index1,index2 或者 DELETE /index*

  • 查看索引的映射 GET /{index}/_mapping

  • 查看某个索引的某个类型的映射 GET /{index}/_mapping/{type}

  • 映射添加新字段 PUT /{index}/_mapping/{type}

PUT /shop/_mapping/goods
{
"properties": {
"params": {
"type": "nested",
"properties": {
"id": { "type": "long" },
"label": { "type": "text" },
"value": { "type": "text" }
}
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
// 插入一条文档
POST /shop/goods
{
"name": "【特别尺码】女装 棉混纺休闲针织衫(长袖) 407767 优衣库UNIQLO",
"price": 149.00,
"quantity": 100,
"colors": ["乳白色", "红色", "黄色"],
"is_discount": true,
"create_date": "2018-01-31 12:10:30",
"ip_addr": "192.168.1.1",
"location": "41.12,-71.34",
"merchant": {
"id": 1111,
"shop_name": "优衣库官方旗舰店"
},
"params": [
{"id": 1, "label":"货号", "value": "7525001123"},
{"id": 2, "label":"品牌", "value": "Cache Cache"}
]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

查询文档 /{index}/{type}/_search

GET /shop/goods/_search
  • 1

修改索引

  • 新增字段
  • 修改字段的数据类型
```
// 创建索引
PUT /school
{
"mappings": {
"students": {
"properties": {
"name": { "type": "text" },
"age": {"type": "long"}
}
}
}
} // 插入一条文档
PUT /school/students/1
{
"name": "张三",
"age": 27
} // 查询映射
GET school/_mapping/students // 添加文档,增加一个新字段height身高
PUT /school/students/2
{
"name": "小明",
"age": 28,
"height": 1.80
} GET school/_mapping/students
// 查看映射可以看到自动将height作为float类型添加到映射里面
"height": {"type": "float"}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

重新索引

尽管可以增加新的类型到索引中,或者增加新的字段到类型中,但是不能添加新的分析器或者对现有的字段做改动。 如果你那么做的话,结果就是那些已经被索引的数据就不正确, 搜索也不能正常工作。

对现有数据的这类改变最简单的办法就是重新索引:用新的设置创建新的索引并把文档从旧的索引复制到新的索引。

为了有效的重新索引所有在旧的索引中的文档,用 scroll 从旧的索引检索批量文档 , 然后用 bulk API 把文档推送到新的索引中。

同时并行运行多个重建索引任务,但是你显然不希望结果有重叠。正确的做法是按日期或者时间 这样的字段作为过滤条件把大的重建索引分成小的任务:

GET /old_index/_search?scroll=1m
{
"query": {
"range": {
"date": {
"gte": "2014-01-01",
"lt": "2014-02-01"
}
}
},
"sort": ["_doc"],
"size": 1000
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

如果旧的索引持续会有变化,你希望新的索引中也包括那些新加的文档。那就可以对新加的文档做重新索引, 但还是要用日期类字段过滤来匹配那些新加的文档。

通过创建新的索引,将数据重新迁移到新索引中,这种变相的更改索引的配置的方式的缺点是改变了原索引的名称(索引名称不允许重复,新索引就要使用新的索引名)。

注意

  • 禁用_all或者通配符,防止误操作

    对一些人来说,能够用单个命令来删除所有数据可能会导致可怕的后果。如果你想要避免意外的大量删除, 你可以在你的 elasticsearch.yml 做如下配置:action.destructive_requires_name: true

    这个设置使删除只限于特定名称指向的数据, 而不允许通过指定 _all 或通配符来删除指定索引库。你同样可以通过 Cluster State API 动态的更新这个设置。

我的微信公众号:

Elasticsearch入门教程(三):Elasticsearch索引&映射的更多相关文章

  1. ElasticSearch入门 第三篇:索引

    这是ElasticSearch 2.4 版本系列的第三篇: ElasticSearch入门 第一篇:Windows下安装ElasticSearch ElasticSearch入门 第二篇:集群配置 E ...

  2. Elasticsearch入门教程(二):Elasticsearch核心概念

    原文:Elasticsearch入门教程(二):Elasticsearch核心概念 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:ht ...

  3. Elasticsearch入门教程(六):Elasticsearch查询(二)

    原文:Elasticsearch入门教程(六):Elasticsearch查询(二) 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:h ...

  4. Elasticsearch入门教程(五):Elasticsearch查询(一)

    原文:Elasticsearch入门教程(五):Elasticsearch查询(一) 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:h ...

  5. Elasticsearch入门教程(一):Elasticsearch及插件安装

    原文:Elasticsearch入门教程(一):Elasticsearch及插件安装 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:h ...

  6. Elasticsearch入门教程(四):Elasticsearch文档CURD

    原文:Elasticsearch入门教程(四):Elasticsearch文档CURD 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接: ...

  7. 无废话ExtJs 入门教程三[窗体:Window组件]

    无废话ExtJs 入门教程三[窗体:Window组件] extjs技术交流,欢迎加群(201926085) 1.代码如下: 1 <!DOCTYPE html PUBLIC "-//W3 ...

  8. PySide——Python图形化界面入门教程(三)

    PySide——Python图形化界面入门教程(三) ——使用内建新号和槽 ——Using Built-In Signals and Slots 上一个教程中,我们学习了如何创建和建立交互widget ...

  9. RabbitMQ入门教程(三):Hello World

    原文:RabbitMQ入门教程(三):Hello World 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog. ...

随机推荐

  1. [CSP-S模拟测试]:爬(贪心)

    题目传送门(内部题134) 输入格式 第一行两个数$N,L$. 接下来$N$行每行两个数$A_i,B_i$. 接下来$N$行每行一个整数$C_i$. 输出格式 一行一个整数表示答案,无解输出$-1$. ...

  2. Mac安装ipython与jupyter

    Python从Python发展而来,更倾向于科学计算.互联网数据分析更喜欢用. 首先切换root用户: sudo su - pip3自动安装ipython yuchaodeMacBook-Pro:~ ...

  3. winscp连接后目录名称乱码

    1.点击[编辑](点后变为保存按钮)按钮,高级按钮变为可用,点击[高级] 2.文件名utf-8编码,默认为“自动”,勾选为“开启”

  4. LeetCode328----奇偶链表

    给定一个单链表,把所有的奇数节点和偶数节点分别排在一起.请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性. 请尝试使用原地算法完成.你的算法的空间复杂度应为 O(1),时 ...

  5. 第十一周Java学习总结。

    java UI 图形界面知识梳理: ATM: 在整个AWT包中提供的所有工具类主要分为以下3种. (1)组件:Component. (2)容器:Container. (3)布局管理器:LayoutMa ...

  6. IDEA 创建maven jar、war、 pom项目

    创建java jar.pom项目时创建maven-archetype-quickstart 创建java war项目时创建maven-archetype-webapp

  7. 初始化EPT

    struct eptp_bits { unsigned memory_type :; /* 0: UC uncacheable, 6: WB writeback */ unsigned pagewal ...

  8. emqtt 系统主题

    $SYS-系统主题 EMQ 消息服务器周期性发布自身运行状态.MQTT 协议统计.客户端上下线状态到 $SYS/ 开头系统主题. $SYS 主题路径以 “$SYS/brokers/{node}/” 开 ...

  9. LoadRunner 技巧之 集合点设置

    LoadRunner 技巧之 集合点设置 Loadrunner 技巧已经整理4篇了,你个一定疑问,这些知识点,网上随处可见.确实,由于长时间没有使用这个工具,造成我的一些概念开始在大脑中模糊,我只是用 ...

  10. Several ports (8005, 8080, 8009) required by Tomcat v8.5 Server at localhost are already in use.

    Several ports (8005, 8080, 8009) required by Tomcat v8.5 Server at localhost are already in use. The ...