-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
479 lines (291 loc) · 298 KB
/
atom.xml
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>MantouDev</title>
<subtitle>🐈 👀</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://mantoudev.com/"/>
<updated>2019-02-24T04:15:50.811Z</updated>
<id>http://mantoudev.com/</id>
<author>
<name>Mantou</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>越来越火的图数据库究竟是什么</title>
<link href="http://mantoudev.com/%E8%B6%8A%E6%9D%A5%E8%B6%8A%E7%81%AB%E7%9A%84%E5%9B%BE%E6%95%B0%E6%8D%AE%E5%BA%93%E7%A9%B6%E7%AB%9F%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F/"/>
<id>http://mantoudev.com/越来越火的图数据库究竟是什么?/</id>
<published>2019-02-24T04:15:00.000Z</published>
<updated>2019-02-24T04:15:50.811Z</updated>
<content type="html"><![CDATA[<blockquote><p>随着社交、电商、金融、零售、物联网等行业的快速发展,现实社会织起了了一张庞大而复杂的关系网,传统数据库很难处理关系运算。大数据行业需要处理的数据之间的关系随数据量呈几何级数增长,亟需一种支持海量复杂数据关系运算的数据库,<code>图数据库</code>应运而生。</p></blockquote><p>世界上很多著名的公司都在使用图数据库。比如:</p><ul><li><strong>社交领域</strong>:Facebook, Twitter,Linkedin用它来管理社交关系,实现好友推荐</li><li><strong>零售领域</strong>:eBay,沃尔玛使用它实现商品实时推荐,给买家更好的购物体验</li><li><strong>金融领域</strong>:摩根大通,花旗和瑞银等银行在用图数据库做风控处理</li><li><strong>汽车制造领域</strong>:沃尔沃,戴姆勒和丰田等顶级汽车制造商依靠图数据库推动创新制造解决方案</li><li><strong>电信领域</strong>:Verizon, Orange和AT&T 等电信公司依靠图数据库来管理网络,控制访问并支持客户360</li><li><strong>酒店领域</strong>:万豪和雅高酒店等顶级酒店公司依使用图数据库来管理复杂且快速变化的库存</li></ul><p>既然图数据库应用这么广泛,越来越多的企业和开发者开始使用它,那它究竟什么过人之处呢,下面我们来揭开它的神秘面纱。<br><a id="more"></a></p><h2 id="1-Why-Graph-DB"><a href="#1-Why-Graph-DB" class="headerlink" title="1. Why Graph DB?"></a>1. Why Graph DB?</h2><p>学过数据结构这么课程的同学脑海中应该或多或少有<code>图</code>的概念。</p><h3 id="1-1-什么是图?"><a href="#1-1-什么是图?" class="headerlink" title="1.1 什么是图?"></a>1.1 什么是图?</h3><p>图由两个元素组成:<code>节点</code>和<code>关系</code>。</p><p>每个节点代表一个实体(人,地,事物,类别或其他数据),每个关系代表两个节点的关联方式。这种通用结构可以对各种场景进行建模 - 从道路系统到设备网络,到人口的病史或由关系定义的任何其他事物。</p><h3 id="1-2-什么是图数据库?"><a href="#1-2-什么是图数据库?" class="headerlink" title="1.2 什么是图数据库?"></a>1.2 什么是图数据库?</h3><p><code>图数据库(Graph database)</code>并非指存储图片的数据库,而是以<code>图</code>这种数据结构存储和查询数据。</p><p><code>图形数据库</code>是一种在线数据库管理系统,具有处理图形数据模型的创建,读取,更新和删除(CRUD)操作。</p><p>与其他数据库不同,<code>关系</code>在图数据库中占首要地位。这意味着应用程序不必使用外键或带外处理(如MapReduce)来推断数据连接。</p><p>与关系数据库或其他NoSQL数据库相比,图数据库的数据模型也更加简单,更具表现力。</p><p>图形数据库是为与事务(OLTP)系统一起使用而构建的,并且在设计时考虑了事务完整性和操作可用性。</p><h3 id="1-3-两个重要属性"><a href="#1-3-两个重要属性" class="headerlink" title="1.3 两个重要属性"></a>1.3 两个重要属性</h3><p>根据存储和处理模型不同,市面上图数据库也有一些区分。</p><p>比如:<br><code>Neo4J</code>就是属于原生图数据库,它使用的后端存储是专门为Neo4J这种图数据库定制和优化的,理论上说能更有利于发挥图数据库的性能。</p><p>而<code>JanusGraph</code>不是原生图数据库,而将数据存储在其他系统上,比如Hbase。 </p><h4 id="①-图存储"><a href="#①-图存储" class="headerlink" title="① 图存储"></a>① 图存储</h4><p>一些图数据库使用<code>原生图存储</code>,这类存储是经过优化的,并且是专门为了存储和管理图而设计的。并不是所有图数据库都是使用原生图存储,也有一些图数据库将图数据序列化,然后保存到关系型数据库或者面向对象数据库,或其他通用数据存储中。</p><h4 id="②-图处理引擎"><a href="#②-图处理引擎" class="headerlink" title="② 图处理引擎"></a>② 图处理引擎</h4><p>原生图处理(也称为<code>无索引邻接</code>)是处理图数据的最有效方法,因为连接的节点在数据库中物理地<strong>指向</strong>彼此。非本机图处理使用其他方法来处理CRUD操作。</p><h2 id="2-对比"><a href="#2-对比" class="headerlink" title="2. 对比"></a>2. 对比</h2><h3 id="2-1-与NoSQL数据库对比"><a href="#2-1-与NoSQL数据库对比" class="headerlink" title="2.1 与NoSQL数据库对比"></a>2.1 与NoSQL数据库对比</h3><p>NoSQL数据库大致可以分为四类:</p><ul><li>键值(key/value)数据库</li><li>列存储数据库</li><li>文档型数据库</li><li>图数据库</li></ul><p><img src="https://s3.amazonaws.com/dev.assets.neo4j.com/wp-content/uploads/20181025032156/nosql-databases-overview.png" alt="NoSQL数据库"></p><table><thead><tr><th>分类</th><th>数据模型</th><th>优势</th><th>劣势</th><th>举例</th></tr></thead><tbody><tr><td>键值数据库</td><td>哈希表</td><td>查找速度快</td><td>数据无结构化,通常只被当作字符串或者二进制数据</td><td>Redis</td></tr><tr><td>列存储数据库</td><td>列式数据存储</td><td>查找速度快;支持分布横向扩展;数据压缩率高</td><td>功能相对受限</td><td>HBase</td></tr><tr><td>文档型数据库</td><td>键值对扩展</td><td>数据结构要求不严格;表结构可变;不需要预先定义表结构</td><td>查询性能不高,缺乏统一的查询语法</td><td>MongoDB</td></tr><tr><td>图数据库</td><td>节点和关系组成的图</td><td>利用图结构相关算法(最短路径、节点度关系查找等)</td><td>可能需要对整个图做计算,不利于图数据分布存储</td><td>Neo4j、JanusGraph</td></tr></tbody></table><h3 id="2-2-与关系型数据库对比"><a href="#2-2-与关系型数据库对比" class="headerlink" title="2.2 与关系型数据库对比"></a>2.2 与关系型数据库对比</h3><p>关系型数据库实际上是不擅长处理关系的。很多场景下,你的业务需求完全超出了当前的数据库架构。</p><p>举个栗子:假设某关系型数据库中有这么几张用户、订单、商品表:</p><p><img src="https://s3.amazonaws.com/dev.assets.neo4j.com/wp-content/uploads/20180716185458/relational-database-rdbms-model-example.jpg" alt="image"></p><p>当我们要查询:“用户购买了那些商品?” 或者 “该商品有哪些客户购买过?” 需要开发人员JOIN几张表,效率非常低下。</p><p>而“购买该产品的客户还购买了哪些商品?”类似的查询几乎不可能实现。</p><p><strong>关系查询性能对比</strong><br>在数据关系中心,图形数据库在查询速度方面非常高效,即使对于深度和复杂的查询也是如此。在《Neo4j in Action》这本书中,作者在关系型数据库<br>和图数据库(Neo4j)之间进行了实验。</p><p><img src="https://s2.ax1x.com/2019/02/21/kR4tKg.md.png" alt="image"></p><p>他们的实验试图在一个社交网络里找到最大深度为5的朋友的朋友。他们的数据集包括100万人,每人约有50个朋友。实验结果如下:</p><table><thead><tr><th>深度</th><th>MySQL执行时间(s)</th><th>Neo4J执行时间(s)</th><th>返回记录数</th></tr></thead><tbody><tr><td>2</td><td>0.016</td><td>0.01</td><td>~2500</td></tr><tr><td>3</td><td>30.267</td><td>0.168</td><td>~110 000</td></tr><tr><td>4</td><td>1543.505</td><td>1.359</td><td>~600 000</td></tr><tr><td>5</td><td>未完成</td><td>2.132</td><td>~800 000</td></tr></tbody></table><p>在深度为2时(即朋友的朋友),两种数据库性能相差不是很明显;深度为3时(即朋友的朋友的朋友),很明显,关系型数据库的响应时间30s,已经变得不可接受了;深度到4时,关系数据库需要近半个小时才能返回结果,使其无法应用于在线系统;深度到5时,关系型数据库已经无法完成查询。而对于图数据库Neo4J,深度从3到5,其响应时间均在3秒以内。</p><p>可以看出,对于图数据库来说,数据量越大,越复杂的关联查询,约有利于体现其优势。从深度为4/5的查询结果我们可以看出,图数据库返回了整个社交网络一半以上的人数。</p><h2 id="3-Neo4J-和-JanuasGraph"><a href="#3-Neo4J-和-JanuasGraph" class="headerlink" title="3. Neo4J 和 JanuasGraph"></a>3. Neo4J 和 JanuasGraph</h2><p>根据DB-Engines最新发布的图数据库排名,Neo4J仍然大幅领先排在第一位:</p><p><img src="https://s2.ax1x.com/2019/02/21/kRfRlF.png" alt="DB-Engines 19年2月图数据库排名"></p><h3 id="Neo4J"><a href="#Neo4J" class="headerlink" title="Neo4J"></a>Neo4J</h3><p><img src="https://neo4j.com/wp-content/themes/neo4jweb/assets/images/neo4j-logo-2015.png" alt="Neo4J"></p><p>Neo4J是由Java实现的开源图数据库。自2003年开始开发,直到2007年正式发布第一版,并托管于GitHub上。</p><p>Neo4J支持ACID,集群、备份和故障转移。目前Neo4J最新版本为3.5,分为社区版和企业版,社区版只支持单机部署,功能受限。企业版支持主从复制和读写分离,包含可视化管理工具。</p><h3 id="JanusGraph"><a href="#JanusGraph" class="headerlink" title="JanusGraph"></a>JanusGraph</h3><p><img src="http://janusgraph.org/images/janusgraph.png" alt="JanusGraph"></p><p>JanusGraph是一个Linux基金会下的开源分布式图数据库 。JanusGraph提供Apache2.0软件许可证。该项目由IBM、Google、Hortonworks支持。JanusGraph是由TitanDB 图数据库修改而来,TitanDB从2012年开始开发。目前最新版本为0.3.1。</p><p>JanusGraph支持多种储存后端(包括Apache Cassandra、Apache HBase、Bigtable、Berkeley DB)。JanusGraph的可扩展性取决于与JanusGraph一起使用的基础技术。例如,通过使用Apache Cassandra作为存储后端,可以将JanusGraph简单地扩展到多个数据中心。</p><p>JanusGraph通过与大数据平台(Apache Spark,Apache Giraph,Apache Hadoop)集成,支持全局图数据的分析、报告和ETL。</p><p>JanusGraph通过外部索引存储(Elasticsearch,Solr,Lucene)支持地理、数字范围和全文搜索。</p><h3 id="3-1-标记属性图模型"><a href="#3-1-标记属性图模型" class="headerlink" title="3.1 标记属性图模型"></a>3.1 标记属性图模型</h3><p><img src="https://s3.amazonaws.com/dev.assets.neo4j.com/wp-content/uploads/20170731095054/Property-Graph-Concepts-Simple.svg" alt="标记属性图模型"></p><h4 id="(1)节点"><a href="#(1)节点" class="headerlink" title="(1)节点"></a>(1)节点</h4><ul><li>节点是主要的数据元素</li><li>节点通过<strong>关系</strong>连接到其他节点</li><li>节点可以具有一个或多个<strong>属性</strong>(即,存储为键/值对的属性)</li><li>节点有一个或多个<strong>标签</strong>,用于描述其在图表中的作用</li><li>示例:人员节点与Car节点</li></ul><h4 id="(2)关系"><a href="#(2)关系" class="headerlink" title="(2)关系"></a>(2)关系</h4><ul><li>关系连接两个节点</li><li>关系是方向性的</li><li><strong>节点</strong>可以有多个甚至递归的关系</li><li>关系可以有一个或多个属性(即存储为键/值对的属性)</li></ul><h4 id="(3)属性"><a href="#(3)属性" class="headerlink" title="(3)属性"></a>(3)属性</h4><ul><li>属性是命名值,其中名称(或键)是字符串</li><li>属性可以被索引和约束</li><li>可以从多个属性创建复合索引</li></ul><h4 id="(4)标签"><a href="#(4)标签" class="headerlink" title="(4)标签"></a>(4)标签</h4><ul><li>标签用于将<strong>节点</strong>分组</li><li>一个节点可以具有多个标签</li><li>对标签进行索引以加速在图中查找节点</li><li>本机标签索引针对速度进行了优化</li></ul><h2 id="4-Cypher图查询语言"><a href="#4-Cypher图查询语言" class="headerlink" title="4. Cypher图查询语言"></a>4. Cypher图查询语言</h2><p>Cypher是Neo4j的图形查询语言,允许用户存储和检索图形数据库中的数据。</p><p>举例,我们要查找Joe的所以二度好友:</p><p><img src="https://s2.ax1x.com/2019/02/21/kRocM8.png" alt="image"></p><p>查询语句如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">MATCH</span><br><span class="line"> (person:Person)-[:KNOWS]-(friend:Person)-[:KNOWS]-</span><br><span class="line"> (foaf:Person)</span><br><span class="line">WHERE</span><br><span class="line"> person.name = "Joe"</span><br><span class="line"> AND NOT (person)-[:KNOWS]-(foaf)</span><br><span class="line">RETURN</span><br><span class="line"> foaf</span><br></pre></td></tr></table></figure></p><p>Joe认识Sally,Sally认识Anna。 Bob被排除在结果之外,因为除了通过Sally成为二级朋友之外,他还是一级朋友。</p><h2 id="5-小结"><a href="#5-小结" class="headerlink" title="5. 小结"></a>5. 小结</h2><p>图数据库应对的是当今一个宏观的商业世界的大趋势:凭借高度关联、复杂的动态数据,获得洞察力和竞争优势。国内越来越多的公司开始进入图数据库领域,研发自己的图数据库系统。对于任何达到一定规模或价值的数据,图数据库都是呈现和查询这些关系数据的最好方式。而理解和分析这些图的能力将成为企业未来最核心的竞争力。</p>]]></content>
<summary type="html">
<blockquote>
<p>随着社交、电商、金融、零售、物联网等行业的快速发展,现实社会织起了了一张庞大而复杂的关系网,传统数据库很难处理关系运算。大数据行业需要处理的数据之间的关系随数据量呈几何级数增长,亟需一种支持海量复杂数据关系运算的数据库,<code>图数据库</code>应运而生。</p>
</blockquote>
<p>世界上很多著名的公司都在使用图数据库。比如:</p>
<ul>
<li><strong>社交领域</strong>:Facebook, Twitter,Linkedin用它来管理社交关系,实现好友推荐</li>
<li><strong>零售领域</strong>:eBay,沃尔玛使用它实现商品实时推荐,给买家更好的购物体验</li>
<li><strong>金融领域</strong>:摩根大通,花旗和瑞银等银行在用图数据库做风控处理</li>
<li><strong>汽车制造领域</strong>:沃尔沃,戴姆勒和丰田等顶级汽车制造商依靠图数据库推动创新制造解决方案</li>
<li><strong>电信领域</strong>:Verizon, Orange和AT&amp;T 等电信公司依靠图数据库来管理网络,控制访问并支持客户360</li>
<li><strong>酒店领域</strong>:万豪和雅高酒店等顶级酒店公司依使用图数据库来管理复杂且快速变化的库存</li>
</ul>
<p>既然图数据库应用这么广泛,越来越多的企业和开发者开始使用它,那它究竟什么过人之处呢,下面我们来揭开它的神秘面纱。<br>
</summary>
<category term="BigData" scheme="http://mantoudev.com/categories/BigData/"/>
<category term="图数据库" scheme="http://mantoudev.com/categories/BigData/%E5%9B%BE%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
<category term="图数据库" scheme="http://mantoudev.com/tags/%E5%9B%BE%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
<category term="Neo4J" scheme="http://mantoudev.com/tags/Neo4J/"/>
<category term="JanusGraph" scheme="http://mantoudev.com/tags/JanusGraph/"/>
</entry>
<entry>
<title>Atlas开发指南(中文版)</title>
<link href="http://mantoudev.com/Atlas%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97(%E4%B8%AD%E6%96%87%E7%89%88)/"/>
<id>http://mantoudev.com/Atlas开发指南(中文版)/</id>
<published>2018-12-01T16:09:50.000Z</published>
<updated>2018-12-02T11:31:52.324Z</updated>
<content type="html"><![CDATA[<blockquote><p>笔者近期在和团队的小伙伴进行数据资产管理方向的探索,本书的翻译基于 <a href="https://atlas.apache.org/" target="_blank" rel="noopener">Apache Atlas v1.1</a> 版本。希望对大家有帮助,阅读过程中遇到问题欢迎留言或与我联系。</p></blockquote><p><a href="/mantouBook/Atlas_cn/index.html">点击我打开《Atlas开发指南(中文版)》</a></p><p>手机端浏览,在Gitbook阅读界面下滑即可看到左上角类似“三”的目录图标,点击即可展开目录进行切换。</p><p>阅读过程中如果有问题,请下方评论中反馈给我~</p>]]></content>
<summary type="html">
<blockquote>
<p>笔者近期在和团队的小伙伴进行数据资产管理方向的探索,本书的翻译基于 <a href="https://atlas.apache.org/" target="_blank" rel="noopener">Apache Atlas v1.1</a> 版
</summary>
<category term="BigData" scheme="http://mantoudev.com/categories/BigData/"/>
<category term="Atlas" scheme="http://mantoudev.com/categories/BigData/Atlas/"/>
<category term="Atlas" scheme="http://mantoudev.com/tags/Atlas/"/>
<category term="Gitbook" scheme="http://mantoudev.com/tags/Gitbook/"/>
<category term="元数据管理" scheme="http://mantoudev.com/tags/%E5%85%83%E6%95%B0%E6%8D%AE%E7%AE%A1%E7%90%86/"/>
</entry>
<entry>
<title>使用Atlas进行元数据管理之容错与高可用</title>
<link href="http://mantoudev.com/%E4%BD%BF%E7%94%A8Atlas%E8%BF%9B%E8%A1%8C%E5%85%83%E6%95%B0%E6%8D%AE%E7%AE%A1%E7%90%86%E4%B9%8B%E5%AE%B9%E9%94%99%E4%B8%8E%E9%AB%98%E5%8F%AF%E7%94%A8/"/>
<id>http://mantoudev.com/使用Atlas进行元数据管理之容错与高可用/</id>
<published>2018-12-01T04:19:40.000Z</published>
<updated>2018-12-02T10:12:32.616Z</updated>
<content type="html"><![CDATA[<h2 id="1-介绍"><a href="#1-介绍" class="headerlink" title="1. 介绍"></a>1. 介绍</h2><p>Apache Atlas使用各种系统并与之交互,为数据管理员提供元数据管理和数据血缘信息。通过适当地选择和配置这些依赖关系,可以使用Atlas实现服务的高可用性。本文档介绍了Atlas中的高可用性支持状态,包括其功能和当前限制,以及实现此高级别可用性所需的配置。<br><a id="more"></a></p><p>在Atlas文档<code>高级架构</code>章节(请参阅我翻译的《Atlas开发指南(中文版)》)概述了构成Atlas的各种组件。下面提到的各种组件的选项,都是基于上述文档中的架构描述,在继续阅读本文之前推荐先行阅读文档中相关章节。</p><h2 id="2-Atlas-Web-Service"><a href="#2-Atlas-Web-Service" class="headerlink" title="2. Atlas Web Service"></a>2. Atlas Web Service</h2><p>目前,Atlas Web Service有一个限制,即它一次只能有一个活动实例。在早期版本的Atlas中,可以配置备份实例并使其可用。但是,需要手动故障转移才能使此备份实例处于活动状态。</p><p>从此版本开始,Atlas将通过自动故障转移支持活动(active)/被动(passive)配置中的多个Atlas Web服务实例。这意味着用户可以同时在不同的物理主机上部署和启动Atlas Web Service的多个实例。其中一个实例将自动选为“active”实例以服务用户请求。其他实例将自动被视为“passive”。如果“active”实例因故意停止或由于意外故障而变得不可用,则其他实例之一将自动被选为“active”实例并开始为用户请求提供服务。</p><p>“active”实例是唯一可以正确响应用户请求的实例。它可以创建,删除,修改或响应元数据对象上的查询。 “passive”实例将接受用户请求,但会使用HTTP重定向将其重定向到当前已知的“active”实例。具体而言,passive实例本身不会响应对元数据对象的任何查询。但是,所有实例(active和passive)都将响应返回有关该实例的信息的管理请求。</p><p>在高可用性模式下配置时,用户可以获得以下操作收益:</p><ul><li><strong>维护间隔期间不间断的服务</strong>:如果需要关闭Atlas Web Service的活动实例以进行维护,则另一个实例将自动变为活动状态并可以为请求提供服务。</li><li><strong>意外故障时的不间断服务</strong>:如果Atlas Web Service的活动实例因软件或硬件错误而失败,则另一个实例将自动变为活动状态并可以为请求提供服务。</li></ul><p>在以下小节中,我们将介绍为Atlas Web Service设置高可用性所需的步骤。我们还描述了如何设计部署和客户端以利用此功能。最后,我们描述了底层实现的一些细节。</p><h3 id="2-1-在Atlas中设置高可用性功能"><a href="#2-1-在Atlas中设置高可用性功能" class="headerlink" title="2.1 在Atlas中设置高可用性功能"></a>2.1 在Atlas中设置高可用性功能</h3><p>设置高可用性功能必须满足以下先决条件。</p><ul><li>确保在一组计算机上安装Apache Zookeeper(建议至少使用3台服务器进行生产)。</li><li>选择2个或更多物理计算机以运行Atlas Web Service实例。这些机器定义了我们称之为Atlas的“服务器集合”。</li></ul><p>要在Atlas中设置高可用性,必须在<code>atlas-application.properties</code>文件中定义一些配置选项。虽然在配置页面中定义了完整的配置项列表,但本节列出了一些主要选项。</p><ul><li>高可用性是Atlas中的可选功能。因此,必须通过将配置选项<code>atlas.server.ha.enabled</code>设置为<code>true</code>来启用它。</li><li>接下来,定义标识符列表,每个物理机一个用于Atlas Web Service实例。这些标识符可以是简单的字符串,如id1,id2等。它们应该是唯一的,不应包含逗号。</li><li>将这些标识符的逗号分隔列表定义为选项<code>atlas.server.ids</code>的值。</li><li><p>对于每台物理计算机,将IP地址/主机名和端口列为配置<code>atlas.server.address.id</code>的值,其中id表示此物理计算机的标识符字符串。</p><ul><li>例如,如果您选择了2台主机名为<code>host1.company.com</code>和<code>host2.company.com</code>的计算机,则可以按如下方式定义配置选项:<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">atlas.server.ids=id1,id2</span><br><span class="line">atlas.server.address.id1=host1.company.com:21000</span><br><span class="line">atlas.server.address.id2=host2.company.com:21000</span><br></pre></td></tr></table></figure></li></ul></li><li><p>定义将由Atlas高可用性功能使用的Zookeeper集群。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">atlas.server.ha.zookeeper.connect=zk1.company.com:2181,zk2.company.com:2181,zk3.company.com:2181</span><br></pre></td></tr></table></figure></li><li><p>您可以查看为高可用性功能定义的其他配置选项,并根据需要在atlas-application.properties文件中进行设置。</p></li><li>对于生产环境,还必须在高可用性模式下设置Atlas所依赖的组件。这将在以下部分中详细介绍。按照这些说明设置和配置它们。</li><li>在所选物理计算机上安装Atlas软件。</li><li>将使用上述步骤创建的atlas-application.properties文件复制到所有计算机的配置目录中。</li><li>启动从属组件。</li><li>启动Atlas Web Service的每个实例。</li></ul><p>要验证高可用性是否正常,请在安装了Atlas Web Service的每个实例上运行以下脚本。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ATLAS_HOME/bin/atlas_admin.py -status</span><br></pre></td></tr></table></figure></p><p>此脚本可以打印以下值之一作为响应:</p><ul><li><strong>ACTIVE</strong>:此实例处于活动状态,可以响应用户请求。</li><li><strong>PASSIVE</strong>:这个实例是被动的。它会将收到的任何用户请求重定向到当前活动实例。</li><li><strong>BECOMING_ACTIVE</strong>:如果服务器正在转换为ACTIVE实例,则会打印出来。服务器无法在此状态下为任何元数据用户请求提供服务。</li><li><strong>BECOMING_PASSIVE</strong>:如果服务器正在转换为PASSIVE实例,则会打印出来。服务器无法在此状态下为任何元数据用户请求提供服务。</li></ul><p>在正常操作情况下,这些实例中只有一个应该打印值ACTIVE作为对脚本的响应,而其他实例将打印PASSIVE。</p><h3 id="2-2-配置客户端以使用高可用性功能"><a href="#2-2-配置客户端以使用高可用性功能" class="headerlink" title="2.2 配置客户端以使用高可用性功能"></a>2.2 配置客户端以使用高可用性功能</h3><p>可以通过两种方式访问Atlas Web Service:</p><ul><li><strong>使用Atlas Web UI</strong>:这是一个基于浏览器的客户端,可用于查询存储在Atlas中的元数据。</li><li><strong>使用Atlas REST API</strong>:由于Atlas公开了RESTful API,因此可以使用任何标准REST客户端,包括其他应用程序中的库。实际上,Atlas附带了一个名为AtlasClient的客户端,可以作为构建REST客户端访问的示例。</li></ul><p>为了利用客户端中的高可用性功能,有两种选择。</p><h4 id="1-使用中间代理"><a href="#1-使用中间代理" class="headerlink" title="(1)使用中间代理"></a>(1)使用中间代理</h4><p>实现对Atlas的高可用性访问的最简单的解决方案是安装和配置一些中间代理,该代理具有基于状态透明地切换服务的能力。一个这样的代理解决方案是<a href="http://www.haproxy.org/" target="_blank" rel="noopener">HAProxy</a>。</p><p>以下是可以使用的示例HAProxy配置。请注意,此提供仅用于说明,而不是推荐的生产配置。请参阅HAProxy文档以获取适当的说明。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">frontend atlas_fe</span><br><span class="line"> bind *:41000</span><br><span class="line"> default_backend atlas_be</span><br><span class="line"></span><br><span class="line">backend atlas_be</span><br><span class="line"> mode http</span><br><span class="line"> option httpchk get /api/atlas/admin/status</span><br><span class="line"> http-check expect string ACTIVE</span><br><span class="line"> balance roundrobin</span><br><span class="line"> server host1_21000 host1:21000 check</span><br><span class="line"> server host2_21000 host2:21000 check backup</span><br><span class="line"></span><br><span class="line">listen atlas</span><br><span class="line"> bind localhost:42000</span><br></pre></td></tr></table></figure></p><p>上面的配置绑定HAProxy以监听端口41000以获取传入的客户端连接。然后,它会根据HTTP状态检查将连接路由到主机host1或host2。状态检查是使用REST URL <code>/api/atlas/admin/status</code>上的HTTP GET完成的,仅当HTTP响应包含字符串ACTIVE时才被视为成功。</p><h4 id="2-使用活动实例自动检测"><a href="#2-使用活动实例自动检测" class="headerlink" title="(2)使用活动实例自动检测"></a>(2)使用活动实例自动检测</h4><p>如果不想设置和管理单独的代理,则使用高可用性功能的另一个选项,是构建能够检测状态和重试操作的客户端应用程序。在这样的设置中,可以使用形成整体的所有Atlas Web Service实例的URL启动客户端应用程序。然后,客户端应在每个上面调用REST <code>URL/api/atlas/admin/status</code>以确定哪个是活动实例。 Active实例的响应形式为<code>{Status:ACTIVE}</code>。此外,当客户端在操作过程中面临任何异常时,它应该再次确定哪些剩余URL处于活动状态并重试该操作。</p><p>Atlas附带的AtlasClient类可用作示例客户端库,该库实现处理集合并选择正确的Active Server实例的逻辑。</p><p>Atlas中的实用程序(如<code>quick_start.py</code>和<code>import-hive.sh</code>)可以配置为与多个服务器URL一起运行。在此模式下启动时,AtlasClient会自动选择并使用当前活动实例。如果在两者之间设置了代理,则在运行<code>quick_start.py</code>或<code>import-hive.sh</code>时可以使用其地址。</p><h3 id="2-3-Atlas高可用性的实现细节"><a href="#2-3-Atlas高可用性的实现细节" class="headerlink" title="2.3 Atlas高可用性的实现细节"></a>2.3 Atlas高可用性的实现细节</h3><p>Atlas高可用性工作在主JIRA <a href="https://issues.apache.org/jira/browse/ATLAS-510" target="_blank" rel="noopener">ATLAS-510</a>下进行跟踪。在其下提交的JIRA提供了有关如何实施高可用性功能的详细信息。在高层次上,可以调出以下几点:</p><ul><li>自动选择Active实例,以及通过领导者选举算法自动故障转移到新的Active实例。</li><li>对于领导者选举,我们使用<a href="http://curator.apache.org/curator-recipes/leader-latch.html" target="_blank" rel="noopener">Leader Latch Recipe</a> of <a href="http://curator.apache.org/" target="_blank" rel="noopener">Apache Curator</a>。</li><li>Active实例是唯一一个在后端存储中初始化,修改或读取状态以保持一致的实例。</li><li>此外,当实例被选为活动时,它会刷新来自后端存储的任何缓存信息以获取最新信息。</li><li>servlet过滤器确保只有活动实例服务用户请求。如果被动实例接收到这些请求,它会自动将它们重定向到当前活动实例。</li></ul><h2 id="3-元数据存储"><a href="#3-元数据存储" class="headerlink" title="3. 元数据存储"></a>3. 元数据存储</h2><p>Atlas使用JanusGraph存储和管理元数据。默认情况下,Atlas使用独立的HBase实例作为JanusGraph的底层存储。为了为元数据存储提供HA,我们建议将Atlas配置为使用分布式HBase作为JanusGraph的底层存储。要将Atlas配置为在HA模式下使用HBase,请执行以下操作:</p><ul><li>选择在HA模式下设置的现有HBase群集,以在Atlas(OR)中进行配置在HA模式下设置新的HBase群集。<ul><li>如果为Atlas设置HBase,请按照Atlas官网“<a href="https://atlas.apache.org/InstallationSteps.html" target="_blank" rel="noopener">Installation Steps</a>”,列出的HBase的相关设置说明进行操作。</li></ul></li><li>建议在使用Zookeeper进行协调的不同物理主机上的群集中使用多个HBase主服务器(至少2个),以提供HBase的冗余和高可用性。</li><li>有关在<code>atlas.properties</code>中配置以使用HBase设置Atlas的选项,请参阅我翻译的<a href="https://mantoudev.com/2018/11/29/Atlas%E4%B8%AD%E6%96%87%E6%96%87%E6%A1%A3/">《Atlas开发指南(中文版)》</a>中“配置”章节。</li></ul><h2 id="4-索引存储"><a href="#4-索引存储" class="headerlink" title="4. 索引存储"></a>4. 索引存储</h2><p>如上所述,Atlas通过JanusGraph索引元数据以支持全文搜索查询。为了给索引存储提供HA,我们建议将Atlas配置为使用<code>Solr</code>或<code>Elasticsearch</code>作为JanusGraph的索引存储支撑。</p><h3 id="4-1-Solr"><a href="#4-1-Solr" class="headerlink" title="4.1 Solr"></a>4.1 Solr</h3><p>要将Atlas配置为在HA模式下使用Solr,请执行以下操作:</p><ul><li>选择HA模式下的现有SolrCloud群集设置以在Atlas中配置(OR)设置新的SolrCloud群集。<ul><li>确保Solr在至少2个物理主机上启用以实现冗余,并且每个主机都运行Solr节点。</li><li>建议将冗余数量设置为至少2个副本。</li></ul></li><li>创建Atlas所需的SolrCloud集合,详见Atlas官网“<a href="https://atlas.apache.org/InstallationSteps.html" target="_blank" rel="noopener">Installation Steps</a>”。</li><li>有关在atlas.properties中配置以使用Solr设置Atlas的选项,请参阅我翻译的<a href="https://mantoudev.com/2018/11/29/Atlas%E4%B8%AD%E6%96%87%E6%96%87%E6%A1%A3/">《Atlas开发指南(中文版)》</a>的文档中“配置”章节。</li></ul><h3 id="4-2-Elasticsearch"><a href="#4-2-Elasticsearch" class="headerlink" title="4.2 Elasticsearch"></a>4.2 Elasticsearch</h3><p>要将Atlas配置为在HA模式下使用Elasticsearch,请执行以下操作:</p><ul><li>选择现有的Elasticsearch集群设置,(或)设置新的集群Elasticsearch集群。</li><li>确保Elasticsearch在至少五个物理主机上启用以实现冗余。</li><li>建议设置分片数量为3</li><li>有关在atlas.properties中配置以使用Elasticsearch设置Atlas的选项,请参阅我翻译的<a href="https://mantoudev.com/2018/11/29/Atlas%E4%B8%AD%E6%96%87%E6%96%87%E6%A1%A3/">《Atlas开发指南(中文版)》</a>的文档中“配置”章节。</li></ul><h2 id="5-通知服务"><a href="#5-通知服务" class="headerlink" title="5. 通知服务"></a>5. 通知服务</h2><p>来自Hook的元数据通知事件通过写入名为<code>ATLAS_HOOK</code>的Kafka Topic发送到Atlas。同样,从Atlas到其他集成组件(如Ranger)的事件也会写入名为<code>ATLAS_ENTITIES</code>的Kafka Topic。由于Kafka持久化这些消息,即使消费者因发送事件而关闭,事件也不会丢失。此外,我们建议Kafka也设置容错,以便它具有更高的可用性保证。要将Atlas配置为在HA模式下使用Kafka,请执行以下操作:</p><ul><li>选择在HA模式下设置的现有Kafka群集,以在Atlas(OR)中配置设置新的Kafka群集。</li><li><p>建议群集中不同的Kafka代理在不同的物理主机上使用Zookeeper进行协调,以提供Kafka的冗余和高可用性。</p><ul><li>设置至少2个物理主机以实现冗余,每个主机托管一个Kafka代理。</li></ul></li><li><p>为Atlas使用设置Kafka主题:</p><ul><li>ATLAS主题的分区数应设置为1(numPartitions)</li><li>确定Kafka主题的副本数量:将此设置为至少2以实现冗余。</li><li>运行以下命令:<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$KAFKA_HOME/bin/kafka-topics.sh --create --zookeeper <list of zookeeper host:port entries> --topic ATLAS_HOOK --replication-factor <numReplicas> --partitions 1</span><br><span class="line">$KAFKA_HOME/bin/kafka-topics.sh --create --zookeeper <list of zookeeper host:port entries> --topic ATLAS_ENTITIES --replication-factor <numReplicas> --partitions 1</span><br><span class="line">Here KAFKA_HOME points to the Kafka installation directory.</span><br></pre></td></tr></table></figure></li></ul></li></ul><p>在<code>atlas-application.properties</code>中,设置以下配置:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">atlas.notification.embedded=false</span><br><span class="line">atlas.kafka.zookeeper.connect=<comma separated list of servers forming Zookeeper quorum used by Kafka></span><br><span class="line">atlas.kafka.bootstrap.servers=<comma separated list of Kafka broker endpoints in host:port form> - Give at least 2 for redundancy.</span><br></pre></td></tr></table></figure></p><h2 id="6-问题"><a href="#6-问题" class="headerlink" title="6. 问题"></a>6. 问题</h2><p>如果托管Atlas表的HBase region servers挂掉,Atlas将无法存储或检索HBase中的元数据,直到它们重新联机。</p>]]></content>
<summary type="html">
<h2 id="1-介绍"><a href="#1-介绍" class="headerlink" title="1. 介绍"></a>1. 介绍</h2><p>Apache Atlas使用各种系统并与之交互,为数据管理员提供元数据管理和数据血缘信息。通过适当地选择和配置这些依赖关系,可以使用Atlas实现服务的高可用性。本文档介绍了Atlas中的高可用性支持状态,包括其功能和当前限制,以及实现此高级别可用性所需的配置。<br>
</summary>
<category term="BigData" scheme="http://mantoudev.com/categories/BigData/"/>
<category term="元数据管理" scheme="http://mantoudev.com/categories/BigData/%E5%85%83%E6%95%B0%E6%8D%AE%E7%AE%A1%E7%90%86/"/>
<category term="元数据管理" scheme="http://mantoudev.com/tags/%E5%85%83%E6%95%B0%E6%8D%AE%E7%AE%A1%E7%90%86/"/>
<category term="atlas" scheme="http://mantoudev.com/tags/atlas/"/>
<category term="血缘" scheme="http://mantoudev.com/tags/%E8%A1%80%E7%BC%98/"/>
</entry>
<entry>
<title>使用Atlas进行元数据管理之Glossary(术语)</title>
<link href="http://mantoudev.com/%E4%BD%BF%E7%94%A8Atlas%E8%BF%9B%E8%A1%8C%E5%85%83%E6%95%B0%E6%8D%AE%E7%AE%A1%E7%90%86%E4%B9%8BGlossary(%E6%9C%AF%E8%AF%AD)/"/>
<id>http://mantoudev.com/使用Atlas进行元数据管理之Glossary(术语)/</id>
<published>2018-11-27T01:39:40.000Z</published>
<updated>2018-11-28T06:28:02.724Z</updated>
<content type="html"><![CDATA[<blockquote><p>背景:笔者和团队的小伙伴近期在进行<strong>数据治理/元数据管理</strong>方向的探索, 在接下来的系列文章中, 会陆续与读者们进行分享在此过程中踩过的坑和收获。</p></blockquote><h2 id="0-当我们谈论数据治理-元数据管理的时候,我们究竟在讨论什么?"><a href="#0-当我们谈论数据治理-元数据管理的时候,我们究竟在讨论什么?" class="headerlink" title="0. 当我们谈论数据治理/元数据管理的时候,我们究竟在讨论什么?"></a>0. 当我们谈论数据治理/元数据管理的时候,我们究竟在讨论什么?</h2><p>谈到数据治理,自然离不开元数据。元数据(Metadata),用一句话定义就是:描述数据的数据。元数据打通了数据源、数据仓库、数据应用,记录了数据从产生到消费的全过程。因此,数据治理的核心就是<code>元数据管理</code>。<br><a id="more"></a></p><p>数据的真正价值在于数据驱动决策,通过数据指导运营。通过数据驱动的方法判断趋势,帮住我们发现问题,继而推动创新或产生新的解决方案。随着企业数据爆发式增长,数据体量越来越难以估量,我们很难说清楚我们到底拥有哪些数据,这些数据从哪里来,到哪里去,发生了什么变化,应该如何使用它们。因此元数据管理(数据治理)成为企业级数据湖不可或缺的重要组成部分。</p><p>可惜很长一段时间内,市面都没有成熟的数据治理解决方案。直到2015年,Hortonworks终于坐不住了,约了一众小伙伴公司倡议:咱们开始整个数据治理方案吧。然后,包含数据分类、集中策略引擎、数据血缘、安全和生命周期管理功能的Atlas应运而生。(PS:另一个应用的较多的元数据开源项目是Linkedin 在2016年新开源的项目:<code>WhereHows</code>)Atlas目前最新的版本为2018年9月18日发布的<code>1.0.0</code>版本。</p><h2 id="1-Atlas介绍"><a href="#1-Atlas介绍" class="headerlink" title="1. Atlas介绍"></a>1. Atlas介绍</h2><p>Atlas 是一个可伸缩和可扩展的核心基础治理服务集合 ,使企业能够有效地和高效地满足 Hadoop 中的合规性要求,并允许与整个企业数据生态系统的集成。</p><p>Apache Atlas为组织提供开放式元数据管理和治理功能,用以构建其数据资产目录,对这些资产进行分类和管理,并为数据科学家,数据分析师和数据治理团队提供围绕这些数据资产的协作功能。</p><p><img src="https://atlas.apache.org/images/twiki/architecture.png" alt="Atlas High Level Architecture"></p><p>关于Atlas的背景讲完了,接下来我们依次来讲Atlas中的几个概念,首先是今天的主角:<code>Glossary</code>。</p><h3 id="1-1-Glossary-术语表-介绍"><a href="#1-1-Glossary-术语表-介绍" class="headerlink" title="1.1 Glossary(术语表) 介绍"></a>1.1 Glossary(术语表) 介绍</h3><p>Atlas的术语表(Glossary)提供了一些适当的“单词”,这些“单词”能彼此进行关连和分类,以便业务用户在使用的时候,即使在不同的上下文中也能很好的理解它们。此外,这些术语也是可以映射到数据资产中的,比如:数据库,表,列等。</p><p>术语表抽象出了和数据相关的专业术语,使得用户能以他们更熟悉的方式去查找和使用数据。</p><h3 id="1-2-术语表功能"><a href="#1-2-术语表功能" class="headerlink" title="1.2 术语表功能"></a>1.2 术语表功能</h3><ul><li>能够使用自然语言(技术术语和/或业务术语)定义丰富的术语词汇表。</li><li>能够将术语在语义上相互关联。</li><li>能够将资产映射到术语表中。</li><li>能够按类别划分这些术语。这为术语增加了更多的上下文。</li><li>允许按层次结构排列类别,能展示更广泛和更精细的范围。</li><li>从元数据中独立管理术语表。</li></ul><h3 id="1-3-术语-Term"><a href="#1-3-术语-Term" class="headerlink" title="1.3 术语(Term)"></a>1.3 术语(Term)</h3><p>对于企业来说术语作用的非常大的。对于有用且有意义的术语,需要围绕其用途和上下文进行分组。 Apache Atlas中的术语必须具有唯一的qualifiedName,可以有相同名称的术语,但它们不能属于同一个术语表。具有相同名称的术语只能存在于不同的术语表中。</p><p>术语名称可以包含空格,下划线和短划线(作为引用单词的自然方式)但不包含“。”或“@”,因为qualifiedName的格式为:<code><术语>@<术语限定名></code>。限定名称可以更轻松地使用特定术语。</p><p>术语只能属于单个术语表,并且它们的生命周期也是相同的,如果删除术语表,则术语也会被删除。术语可以属于零个或多个类别,这允许将它们限定为更小或更大的上下文。</p><p>可以在Apache Atlas中为一个或多个实体分配/链接一个术语。可以使用分类(<code>classifications</code>,类似标签的作用)对术语进行分类,并将相同的分类应用于分配术语的实体。</p><h3 id="1-4-类别-Category"><a href="#1-4-类别-Category" class="headerlink" title="1.4 类别(Category)"></a>1.4 类别(Category)</h3><p>类别是组织术语的一种方式,以便可以丰富术语的上下文。</p><p>类别可能包含也可能不包含层次结构,即子类别层次结构。类别的qualifiedName是使用它在术语表中的分层位置导出的,例如:<code><类别名称>.<父类别限定名></code>。当发生任何层级更改时,此限定名称都会更新,例如:添加父类别,删除父类别或更改父类别。</p><h2 id="2-Atlas-Web-UI"><a href="#2-Atlas-Web-UI" class="headerlink" title="2. Atlas Web UI"></a>2. Atlas Web UI</h2><p>Apache Atlas UI提供了友好的用户界面,可以使用术语表相关的功能,其中包括:</p><ul><li>创建术语表,术语和类别</li><li>在术语之间创建各种关系: synonymns(同义词),antonymns(反义词),seeAlso(参考)</li><li>调整类别的层次结构中</li><li>为实体分配实体(entities)</li><li>使用关联术语搜索实体</li></ul><p>与术语表相关的UI都可以在<code>GLOSSARY</code>的Tab下找到。</p><h3 id="2-1-Glossary-Tab"><a href="#2-1-Glossary-Tab" class="headerlink" title="2.1 Glossary Tab"></a>2.1 Glossary Tab</h3><p>Apache Atlas UI提供了两种使用术语表的方法: <code>术语(Terms)视图</code>和<code>类别(Category)视图</code>。</p><h4 id="1-术语视图-Terms"><a href="#1-术语视图-Terms" class="headerlink" title="(1) 术语视图(Terms)"></a>(1) 术语视图(Terms)</h4><p>术语视图允许用户执行以下操作:</p><ul><li>创建,更新和删除术语</li><li>添加,删除和更新与术语关联的分类</li><li>添加,删除和更新术语的分类</li><li>在术语之间创建各种关系</li><li>查看与术语关联的实体</li></ul><h4 id="2-类别视图-Category"><a href="#2-类别视图-Category" class="headerlink" title="(2) 类别视图(Category)"></a>(2) 类别视图(Category)</h4><p>类别视图允许用户执行以下操作:</p><ul><li>创建,更新和删除类别和子类别</li><li>将术语与类别相关联</li></ul><p>用户可以使用术语表选项卡中提供的切换在术语视图和类别视图之间切换。<br><img src="https://atlas.apache.org/images/markdown/terms_view.png" alt="术语视图"></p><p><img src="https://atlas.apache.org/images/markdown/category_view_1.png" alt="分类视图"></p><h3 id="2-2-术语视图-Terms"><a href="#2-2-术语视图-Terms" class="headerlink" title="2.2 术语视图(Terms)"></a>2.2 术语视图(Terms)</h3><ul><li>创建一个新术语<br>单击术语表名称旁边的省略号(…)会显示一个弹出式菜单,允许用户在术语表中创建术语或删除术语表 - 如下所示。<br><img src="https://atlas.apache.org/images/markdown/term_view_context.png" alt="创建术语"></li></ul><ul><li>删除一个术语<br>单击术语名称旁边的省略号(…)会显示一个弹出式菜单,允许用户删除该术语 - 如下所示。<br><img src="https://atlas.apache.org/images/markdown/term_delete_context.png" alt="删除术语"></li></ul><h4 id="2-2-1-术语详情"><a href="#2-2-1-术语详情" class="headerlink" title="2.2.1 术语详情"></a>2.2.1 术语详情</h4><p>选择术语表UI中的术语,可以查看对应术语的各种详细信息。详细信息页面下的每个选项卡提供该术语的不同详细信息。</p><ul><li><code>Entities(实体)</code>选项卡:显示分配给所选术语的实体</li><li><code>Classifications(分类)</code>选项卡:显示与所选术语关联的分类</li><li><code>Related terms (相关术语)</code>选项卡:显示与所选术语相关的术语<br><img src="https://atlas.apache.org/images/markdown/term_details.png" alt="术语详情"></li></ul><h4 id="2-2-2-给术语添加分类-classification"><a href="#2-2-2-给术语添加分类-classification" class="headerlink" title="2.2.2 给术语添加分类(classification)"></a>2.2.2 给术语添加分类(classification)</h4><p>单击分类标签旁边的<code>+</code>可为术语添加分类。<br><img src="https://atlas.apache.org/images/markdown/term_add_classification_1.png" alt="添加分类1"></p><p><img src="https://atlas.apache.org/images/markdown/term_add_classification_2.png" alt="添加分类2"></p><p><img src="https://atlas.apache.org/images/markdown/term_with_classification.png" alt="添加分类3"></p><h4 id="2-2-3-与其他术语建立术语关联"><a href="#2-2-3-与其他术语建立术语关联" class="headerlink" title="2.2.3 与其他术语建立术语关联"></a>2.2.3 与其他术语建立术语关联</h4><p>查看术语详细信息时,单击<code>Related Terms(相关术语)</code>选项卡。单击<code>+</code>将术语与当前术语链接。<br><img src="https://atlas.apache.org/images/markdown/terms_related_terms.png" alt="关联"></p><h4 id="2-2-4-对术语进行分类"><a href="#2-2-4-对术语进行分类" class="headerlink" title="2.2.4 对术语进行分类"></a>2.2.4 对术语进行分类</h4><p>单击类别标签旁边的<code>+</code>可对术语进行分类。将提供模态对话框以选择类别。<br><img src="https://atlas.apache.org/images/markdown/term_add_category.png" alt="分类"></p><h3 id="2-3-类别视图-Category"><a href="#2-3-类别视图-Category" class="headerlink" title="2.3 类别视图(Category)"></a>2.3 类别视图(Category)</h3><p>当切换开关处于<code>Category</code>时,左侧面板将列出所有术语表以及类别层次结构。</p><p><img src="https://atlas.apache.org/images/markdown/category_view_2.png" alt="image"></p><h4 id="2-3-1-类别菜单-Category"><a href="#2-3-1-类别菜单-Category" class="headerlink" title="2.3.1 类别菜单(Category)"></a>2.3.1 类别菜单(Category)</h4><p>单击<code>Category</code>旁边的省略号<code>...</code>将显示类别上下文菜单。</p><ul><li><p>创建新类别<br><img src="https://atlas.apache.org/images/markdown/category_view_glossary_context.png" alt="创建类别"></p></li><li><p>创建子类别或删除类别<br><img src="https://atlas.apache.org/images/markdown/category_view_category_context_1.png" alt="创建/删除子类别"></p></li></ul><h4 id="2-3-2-类别详情"><a href="#2-3-2-类别详情" class="headerlink" title="2.3.2 类别详情"></a>2.3.2 类别详情</h4><p>选择<code>Category</code>后,详细信息将显示在右侧窗口中。</p><p><img src="https://atlas.apache.org/images/markdown/category_details_with_terms.png" alt="分类详情"></p><h4 id="2-3-3-术语分类"><a href="#2-3-3-术语分类" class="headerlink" title="2.3.3 术语分类"></a>2.3.3 术语分类</h4><p>单击详情页中<code>Terms</code>标签旁边的<code>+</code>链接所选类别下的术语。</p><p><img src="https://atlas.apache.org/images/markdown/category_add_term.png" alt="术语分类1"></p><p><img src="https://atlas.apache.org/images/markdown/category_add_term_1.png" alt="术语分类2"></p><p><img src="https://atlas.apache.org/images/markdown/category_add_term_2.png" alt="术语分类3"></p><h2 id="3-术语分配流程"><a href="#3-术语分配流程" class="headerlink" title="3. 术语分配流程"></a>3. 术语分配流程</h2><p>可以在搜索结果页和<code>Glossary-Terms</code>实体详情页中给<code>entity(实体)</code>分配术语。</p><h3 id="3-1-分配术语"><a href="#3-1-分配术语" class="headerlink" title="3.1 分配术语"></a>3.1 分配术语</h3><p>在搜索结果页面,点击<code>terms</code>列下的<code>+</code></p><p><img src="https://atlas.apache.org/images/markdown/entity_search_add_term.png" alt="分配术语1"></p><p>点击<code>terms</code>标签旁边的<code>+</code><br><img src="https://atlas.apache.org/images/markdown/entity_details_add_term.png" alt="分配术语2"></p><p>这两个操作都将显示下面的结果,按照屏幕上的提示完成术语分配。<br><img src="https://atlas.apache.org/images/markdown/entity_add_term_modal.png" alt="完成术语分配"></p><h3 id="3-2-分类传播-Propagated-classification"><a href="#3-2-分类传播-Propagated-classification" class="headerlink" title="3.2 分类传播(Propagated classification)"></a>3.2 分类传播(Propagated classification)</h3><p>如果一个术语具有分类,则该术语下的实体继承相同的分类。</p><p><img src="https://atlas.apache.org/images/markdown/term_details_with_classification.png" alt="image"></p><p><img src="https://atlas.apache.org/images/markdown/entity_assigned_term_with_tag.png" alt="image"></p><h3 id="3-3-使用术语搜索"><a href="#3-3-使用术语搜索" class="headerlink" title="3.3. 使用术语搜索"></a>3.3. 使用术语搜索</h3><p>Apache Atlas基本搜索API和UI已更新,以支持术语作为搜索条件。允许用户查找与给定术语相关联的实体。</p><p><img src="https://atlas.apache.org/images/markdown/term_search.png" alt="搜索"></p><h2 id="4-REST-API"><a href="#4-REST-API" class="headerlink" title="4. REST API"></a>4. REST API</h2><p>Atlas支持以下操作,可在<a href="https://atlas.apache.org/1.1.0/api/v2/index.html" target="_blank" rel="noopener">这里</a>找到REST接口的详细信息。</p><p><img src="https://s1.ax1x.com/2018/11/15/ivYkdI.png" alt="Glossary REST API"><br><img src="https://s1.ax1x.com/2018/11/15/ivYVFP.png" alt="Glossary REST API"></p><h2 id="5-JSON结构"><a href="#5-JSON结构" class="headerlink" title="5. JSON结构"></a>5. JSON结构</h2><ul><li>Glossary</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> "guid": "2f341934-f18c-48b3-aa12-eaa0a2bfce85",</span><br><span class="line"> "qualifiedName": "SampleBank",</span><br><span class="line"> "displayName": "Banking",</span><br><span class="line"> "shortDescription": "Glossary of bank",</span><br><span class="line"> "longDescription": "Glossary of bank - long description",</span><br><span class="line"> "language": "English",</span><br><span class="line"> "usage": "N/A",</span><br><span class="line"> "terms": [</span><br><span class="line"> {</span><br><span class="line"> "termGuid": "502d34f1-b85f-4ad9-9d9f-fe7020ff0acb",</span><br><span class="line"> "relationGuid": "6bb803e4-3af6-4924-aad6-6ad9f95ecd14",</span><br><span class="line"> "displayText": "A savings account"</span><br><span class="line"> }, {</span><br><span class="line"> "termGuid": "e441a540-ee55-4fc8-8eaf-4b9943d8929c",</span><br><span class="line"> "relationGuid": "dbc46795-76ff-4f68-9043-be0eff0bc0f3",</span><br><span class="line"> "displayText": "15-30 yr mortgage"</span><br><span class="line"> }, {</span><br><span class="line"> "termGuid": "998e3692-51a8-47fe-b3a0-0d9f794437eb",</span><br><span class="line"> "relationGuid": "0dcd31b9-a81c-4185-ad4b-9209a97c305b",</span><br><span class="line"> "displayText": "A checking account"</span><br><span class="line"> }, {</span><br><span class="line"> "termGuid": "c4e2b956-2589-4648-8596-240d3bea5e44",</span><br><span class="line"> "relationGuid": "e71c4a5d-694b-47a5-a41e-126ade857279",</span><br><span class="line"> "displayText": "ARM loans"</span><br><span class="line"> }],</span><br><span class="line"> "categories": [{</span><br><span class="line"> "categoryGuid": "dd94859e-7453-4bc9-b634-a17fc14590f8",</span><br><span class="line"> "parentCategoryGuid": "e6a3df1f-5670-4f9e-84da-91f77d008ce3",</span><br><span class="line"> "relationGuid": "a0b7da02-1ccd-4415-bc54-3d0cdb8857e7",</span><br><span class="line"> "displayText": "Accounts"</span><br><span class="line"> }, {</span><br><span class="line"> "categoryGuid": "e6a3df1f-5670-4f9e-84da-91f77d008ce3",</span><br><span class="line"> "relationGuid": "0e84a358-a4aa-4bd3-b806-497a6962ae1d",</span><br><span class="line"> "displayText": "Customer"</span><br><span class="line"> }, {</span><br><span class="line"> "categoryGuid": "7f041401-de8c-443f-a3b7-7bf5a910ff6f",</span><br><span class="line"> "parentCategoryGuid": "e6a3df1f-5670-4f9e-84da-91f77d008ce3",</span><br><span class="line"> "relationGuid": "7757b031-4e25-43a8-bf77-946f7f06c67a",</span><br><span class="line"> "displayText": "Loans"</span><br><span class="line"> }]</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>Term</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> "guid": "e441a540-ee55-4fc8-8eaf-4b9943d8929c",</span><br><span class="line"> "qualifiedName": "fixed_mtg@SampleBank",</span><br><span class="line"> "displayName": "15-30 yr mortgage",</span><br><span class="line"> "shortDescription": "Short description",</span><br><span class="line"> "longDescription": "Long description",</span><br><span class="line"> "examples": ["N/A"],</span><br><span class="line"> "abbreviation": "FMTG",</span><br><span class="line"> "anchor": {</span><br><span class="line"> "glossaryGuid": "2f341934-f18c-48b3-aa12-eaa0a2bfce85",</span><br><span class="line"> "relationGuid": "dbc46795-76ff-4f68-9043-be0eff0bc0f3"</span><br><span class="line"> },</span><br><span class="line"> "categories": [{</span><br><span class="line"> "categoryGuid": "7f041401-de8c-443f-a3b7-7bf5a910ff6f",</span><br><span class="line"> "relationGuid": "b4cddd33-7b0c-41e2-9324-afe549ec6ada",</span><br><span class="line"> "displayText": "Loans"</span><br><span class="line"> }],</span><br><span class="line"> "seeAlso" : [],</span><br><span class="line"> "synonyms" : [],</span><br><span class="line"> "antonyms" : [],</span><br><span class="line"> "replacedBy" : [],</span><br><span class="line"> "replacementTerms" : [],</span><br><span class="line"> "translationTerms" : [],</span><br><span class="line"> "translatedTerms" : [],</span><br><span class="line"> "isA" : [],</span><br><span class="line"> "classifies" : [],</span><br><span class="line"> "preferredTerms" : [],</span><br><span class="line"> "preferredToTerms": [ {</span><br><span class="line"> "termGuid" : "c4e2b956-2589-4648-8596-240d3bea5e44",</span><br><span class="line"> "displayText": "ARM Loans"</span><br><span class="line"> }]</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>Category</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> "guid": "7f041401-de8c-443f-a3b7-7bf5a910ff6f",</span><br><span class="line"> "qualifiedName": "Loans.Customer@HortoniaBank",</span><br><span class="line"> "displayName": "Loans",</span><br><span class="line"> "shortDescription": "Loan categorization",</span><br><span class="line"> "anchor": {</span><br><span class="line"> "glossaryGuid": "2f341934-f18c-48b3-aa12-eaa0a2bfce85",</span><br><span class="line"> "relationGuid": "7757b031-4e25-43a8-bf77-946f7f06c67a"</span><br><span class="line"> },</span><br><span class="line"> "parentCategory": {</span><br><span class="line"> "categoryGuid": "e6a3df1f-5670-4f9e-84da-91f77d008ce3",</span><br><span class="line"> "relationGuid": "8a0a8e11-0bb5-483b-b7d6-cfe0b1d55ef6"</span><br><span class="line"> },</span><br><span class="line"> "childrenCategories" : [],</span><br><span class="line"> "terms": [{</span><br><span class="line"> "termGuid": "e441a540-ee55-4fc8-8eaf-4b9943d8929c",</span><br><span class="line"> "relationGuid": "b4cddd33-7b0c-41e2-9324-afe549ec6ada",</span><br><span class="line"> "displayText": "15-30 yr mortgage"</span><br><span class="line"> }, {</span><br><span class="line"> "termGuid": "c4e2b956-2589-4648-8596-240d3bea5e44",</span><br><span class="line"> "relationGuid": "8db1e784-4f04-4eda-9a58-6c9535a95451",</span><br><span class="line"> "displayText": "ARM loans"</span><br><span class="line"> }]</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="5-1-CURD"><a href="#5-1-CURD" class="headerlink" title="5.1 CURD"></a>5.1 CURD</h3><h4 id="(1)创建操作-CREATE"><a href="#(1)创建操作-CREATE" class="headerlink" title="(1)创建操作(CREATE)"></a>(1)创建操作(CREATE)</h4><ol><li>创建术语表</li><li>创建一个术语</li><li>创建分类术语</li><li>用关系创建术语</li><li>创建一个类别</li><li>创建具有层次结构的类别</li><li>创建类别并对术语进行分类</li><li>为实体分配术语</li></ol><p><strong>注意:</strong></p><ul><li>在创建操作期间,术语表,术语和类别将获得自动分配的GUID和qualifiedName。</li><li>要创建包含子项的类别,必须事先创建子项。</li><li>要创建属于某个类别的术语,必须事先创建该类别。</li><li>要创建关系术语,必须事先创建相关术语。</li></ul><h4 id="(2)读操作-READ"><a href="#(2)读操作-READ" class="headerlink" title="(2)读操作(READ)"></a>(2)读操作(READ)</h4><ol><li>通过GUID获取术语表 - 提供属于术语表的所有术语和类别(标题)。 </li><li>获取所有术语表 - 为所有术语表提供他们的术语和类别(标题)。 </li><li>通过GUID获取术语 - 提供有关术语,其所属类别(如果有)以及任何相关术语的详细信息。</li><li>通过GUID获取类别 - 提供有关类别,类别层次结构(如果有)和属于该类别的术语的详细信息。</li><li>获取给定术语表的所有术语 - 提供属于给定术语表的所有术语(具有#3中提到的详细信息)。</li><li>获取给定术语表的所有类别 - 提供属于给定术语表的所有类别(具有#4中提到的详细信息)。</li><li>获取与给定术语相关的所有术语 - 提供与给定术语相关/链接的所有术语。</li><li>获取与给定类别(父母和子女)相关的所有类别</li><li>获取给定类别的所有条款</li></ol><h4 id="(3)更新操作-UPDATE"><a href="#(3)更新操作-UPDATE" class="headerlink" title="(3)更新操作(UPDATE)"></a>(3)更新操作(UPDATE)</h4><ol><li>局部更新术语表</li><li>局部更新术语</li><li>局部更新类别</li><li>更新给定的词汇表</li><li>更新给定的术语</li><li>更新给定的类别</li></ol><p><strong>注意:</strong></p><ul><li>局部更新仅处理词汇表模型文件中定义的<strong>原始属性</strong>。</li><li>分配后,无法更改GUID和qualifiedName。唯一的方法是删除并重新创建所需的对象。</li><li>在任何更新中都无法删除<strong>锚点</strong></li><li>更新API期望在GET调用之后就地修改JSON。任何缺失的属性/关系都将被删除。</li><li>对类别层次结构的任何更新都会导致对其下的层次结构进行级联更新,例如锚更改会影响所有子项,父项更改会影响self和children的qualifiedName。</li></ul><h4 id="(4)删除操作-DELETE"><a href="#(4)删除操作-DELETE" class="headerlink" title="(4)删除操作(DELETE)"></a>(4)删除操作(DELETE)</h4><ol><li>删除术语表 - 删除锚定到给定词汇表的所有类别和术语。如果已为实体分配任何术语,则会阻止此删除。</li><li>删除术语 - 仅当术语未与任何实体关联/分配时才删除该术语。</li><li>删除类别 - 仅删除给定类别,所有子项都成为顶级类别。</li><li>从实体中删除术语分配</li></ol>]]></content>
<summary type="html">
<blockquote>
<p>背景:笔者和团队的小伙伴近期在进行<strong>数据治理/元数据管理</strong>方向的探索, 在接下来的系列文章中, 会陆续与读者们进行分享在此过程中踩过的坑和收获。</p>
</blockquote>
<h2 id="0-当我们谈论数据治理-元数据管理的时候,我们究竟在讨论什么?"><a href="#0-当我们谈论数据治理-元数据管理的时候,我们究竟在讨论什么?" class="headerlink" title="0. 当我们谈论数据治理/元数据管理的时候,我们究竟在讨论什么?"></a>0. 当我们谈论数据治理/元数据管理的时候,我们究竟在讨论什么?</h2><p>谈到数据治理,自然离不开元数据。元数据(Metadata),用一句话定义就是:描述数据的数据。元数据打通了数据源、数据仓库、数据应用,记录了数据从产生到消费的全过程。因此,数据治理的核心就是<code>元数据管理</code>。<br>
</summary>
<category term="BigData" scheme="http://mantoudev.com/categories/BigData/"/>
<category term="元数据管理" scheme="http://mantoudev.com/categories/BigData/%E5%85%83%E6%95%B0%E6%8D%AE%E7%AE%A1%E7%90%86/"/>
<category term="元数据管理" scheme="http://mantoudev.com/tags/%E5%85%83%E6%95%B0%E6%8D%AE%E7%AE%A1%E7%90%86/"/>
<category term="atlas" scheme="http://mantoudev.com/tags/atlas/"/>
<category term="血缘" scheme="http://mantoudev.com/tags/%E8%A1%80%E7%BC%98/"/>
</entry>
<entry>
<title>[大数据安全]基于Kerberos的大数据安全方案</title>
<link href="http://mantoudev.com/%5B%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%AE%89%E5%85%A8%5D%E5%9F%BA%E4%BA%8EKerberos%E7%9A%84%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%AE%89%E5%85%A8%E6%96%B9%E6%A1%88/"/>
<id>http://mantoudev.com/[大数据安全]基于Kerberos的大数据安全方案/</id>
<published>2018-11-26T13:39:40.000Z</published>
<updated>2018-11-28T06:19:18.725Z</updated>
<content type="html"><![CDATA[<h3 id="1-背景"><a href="#1-背景" class="headerlink" title="1.背景"></a>1.背景</h3><p>互联网从来就不是一个安全的地方。很多时候我们过分依赖防火墙来解决安全的问题,不幸的是,防火墙是假设“坏人”是来自外部的,而真正具有破坏性的攻击事件都是往往都是来自于内部的。</p><p>近几年,在<code>thehackernews</code>等网站上总会时不时的看到可以看到一些因为数据安全问题被大面积攻击、勒索的事件。在Hadoop1.0.0之前,Hadoop并不提供对安全的支持,默认集群内所有角色都是可靠的。用户访问时不需要进行任何验证,导致恶意用户很容易就可以伪装进入集群进行破坏。<br><a id="more"></a></p><p><img src="https://s1.ax1x.com/2018/11/03/i4WMu9.png" alt="不安全的Hadoop集群"></p><p>要保证Hadoop集群的安全,至少要做到2个A:<code>Authentication</code>(认证),<code>Authorization</code>(授权)。常见的方案有:</p><ul><li><strong>Authentication</strong>:<br>MIT Kerberos, Azure AD, Kerby</li><li><strong>Authorization</strong>:<br>Apache Sentry(Cloudera), Apache Ranger(Hortonworks)</li></ul><p><img src="https://s1.ax2x.com/2018/10/30/5XI5Nu.png" alt="Hadoop Cluster Secure"></p><h4 id="Hadoop集群对Kerberos的支持"><a href="#Hadoop集群对Kerberos的支持" class="headerlink" title="Hadoop集群对Kerberos的支持"></a>Hadoop集群对Kerberos的支持</h4><p>2012年1.0.0版本正式发布后,Hadoop才增加了对Kerberos的支持, 使得集群中的节点是可信任的。</p><p>Kerberos可以将认证的密钥在集群部署时事先放到可靠的节点上。集群运行时,集群内的节点使用密钥得到认证,认证通过后的节点才能提供服务。企图冒充的节点由于没有事先得到的密钥信息,无法与集群内部的节点通信。这样就防止了恶意地使用或篡改Hadoop集群的问题,确保了Hadoop集群的可靠性、安全性。</p><h3 id="2-Kerberos介绍"><a href="#2-Kerberos介绍" class="headerlink" title="2.Kerberos介绍"></a>2.Kerberos介绍</h3><p>Kerberos是种网络身份验证协议,最初设计是用来保护雅典娜工程的网络服务器。Kerberos这个名字源于希腊神话,是一只三头犬的名字,它旨在通过使用密钥加密技术为Client/Server序提供强身份验证。可以用于防止窃听、防止重放攻击、保护数据完整性等场合,是一种应用对称密钥体制进行密钥管理的系统。Kerberos的扩展产品也使用公开密钥加密方法进行认证。</p><p>Kerberos目前最新版本是5,1~3版本只在MIT内部发行,因为使用DES加密,早期被美国出口管制局列为军需品禁止出口,直到瑞典皇家工学院实现了Kerberos版本4,KTH-KRB。后续也是这个团队实现了版本5: Heimdal,目前常见的Kerberos5实现之一。</p><p>本文中讨论的Kerberos5实现版本为MIT Kerberos,MIT保持的大约半年左右一次的更新速度,目前最新版本是2018-11-01发布的1.16.2版本。</p><h4 id="2-1-名词解释"><a href="#2-1-名词解释" class="headerlink" title="2.1 名词解释"></a>2.1 名词解释</h4><ul><li>AS(Authentication Server):认证服务器</li><li>KDC(Key Distribution Center):密钥分发中心</li><li>TGT(Ticket Granting Ticket):票据授权票据,票据的票据</li><li>TGS(Ticket Granting Server):票据授权服务器</li><li>SS(Service Server):特定服务提供端</li><li>Principal:被认证的个体</li><li>Ticket:票据,客户端用来证明身份真实性。包含:用户名,IP,时间戳,有效期,会话秘钥。</li></ul><p>使用Kerberos时,一个客户端需要经过三个步骤来获取服务:</p><ol><li><code>认证</code>: 客户端向认证服务器发送一条报文,获取一个包含时间戳的TGT。 </li><li><code>授权</code>: 客户端使用TGT向TGS请求指定Service的Ticket。</li><li><code>服务请求</code>: 客户端向指定的Service出示服务Ticket鉴权通讯。</li></ol><p>Kerberos协议在网络通信协定中属于显示层。其通信流程简单地说,用户先用共享密钥从某认证服务器得到一个身份证明。随后,用户使用这个身份证明与SS通信,而不使用共享密钥。</p><h4 id="2-2-具体通信流程"><a href="#2-2-具体通信流程" class="headerlink" title="2.2 具体通信流程"></a>2.2 具体通信流程</h4><blockquote><p>①此流程使用了对称加密; ②此流程发生在某一个Kerberos领域中; ③小写字母c,d,e,g是客户端发出的消息,大写字母A,B,E,F,H是各个服务器发回的消息。</p></blockquote><p>首先,用户使用客户端上的程序进行登录:</p><ol><li>输入用户ID和密码到客户端(或使用keytab登录)。</li><li>客户端程序运行一个单向函数(大多数为Hash)把密码转换成密钥,这个就是客户端的“用户密钥”(user’s secret key)。</li></ol><h5 id="2-2-1-客户端认证(Kinit)"><a href="#2-2-1-客户端认证(Kinit)" class="headerlink" title="2.2.1 客户端认证(Kinit)"></a>2.2.1 客户端认证(Kinit)</h5><p>客户端(Client)从认证服务器(AS)获取票据的票据(TGT)。<br><img src="https://s1.ax2x.com/2018/10/30/5XIYmr.png" alt="客户端认证"></p><ol><li><p>Client向AS发送1条明文消息,申请基于该用户所应享有的服务,例如“用户Sunny想请求服务”(Sunny是用户ID)。(注意:用户不向AS发送“用户密钥”(user’s secret key),也不发送密码)该AS能够从本地数据库中查询到该申请用户的密码,并通过相同途径转换成相同的“用户密钥”(user’s secret key)。</p></li><li><p>AS检查该用户ID是否在于本地数据库中,如果用户存在则返回2条消息:</p><ul><li>【消息A】:<strong>Client/TGS会话密钥(Client/TGS Session Key)</strong>(该Session Key用在将来Client与TGS的通信(会话)上),通过 <strong>用户密钥(user’s secret key)</strong> 进行加密。</li><li>【消息B】:<strong>票据授权票据(TGT)</strong>(TGT包括:消息A中的“Client/TGS会话密钥”(Client/TGS Session Key),用户ID,用户网址,TGT有效期),通过<strong>TGS密钥(TGS’s secret key)</strong> 进行加密。</li></ul></li><li><p>一旦Client收到消息A和消息B,Client首先尝试用自己的“用户密钥”(user’s secret key)解密消息A,如果用户输入的密码与AS数据库中的密码不符,则不能成功解密消息A。输入正确的密码并通过随之生成的”user’s secret key”才能解密消息A,从而得到“Client/TGS会话密钥”(Client/TGS Session Key)。(注意:Client不能解密消息B,因为B是用TGS密钥(TGS’s secret key)加密的)。拥有了“Client/TGS会话密钥”(Client/TGS Session Key),Client就足以通过TGS进行认证了。</p></li></ol><h5 id="2-2-2-服务授权"><a href="#2-2-2-服务授权" class="headerlink" title="2.2.2 服务授权"></a>2.2.2 服务授权</h5><blockquote><p>Client从TGS获取票据(client-to-server ticket)。</p></blockquote><p><img src="https://s1.ax2x.com/2018/10/30/5XIziR.png" alt="服务授权"></p><ol><li><p>当client需要申请特定服务时,其向TGS发送以下2条消息:</p><ul><li>【消息c】:即消息B的内容(TGS’s secret key加密后的TGT),和想获取的服务的服务ID(注意:不是用户ID)。</li><li>【消息d】:<strong>认证符(Authenticator)</strong>(Authenticator包括:用户ID,时间戳),通过<strong>Client/TGS会话密钥(Client/TGS Session Key)</strong>进行加密。</li></ul></li><li><p>收到消息c和消息d后,TGS首先检查KDC数据库中是否存在所需的服务,查找到之后,TGS用自己的“TGS密钥”(TGS’s secret key)解密消息c中的消息B(也就是TGT),从而得到之前生成的“Client/TGS会话密钥”(Client/TGS Session Key)。TGS再用这个Session Key解密消息d得到包含用户ID和时间戳的Authenticator,并对TGT和Authenticator进行验证,验证通过之后返回2条消息:</p><ul><li>【消息E】:<strong>client-server票据(client-to-server ticket)</strong>(该ticket包括:Client/SS会话密钥 (Client/Server Session Key),用户ID,用户网址,有效期),通过提供该服务的<strong>服务器密钥(service’s secret key)</strong> 进行加密。</li><li>【消息F】:<strong>Client/SS会话密钥( Client/Server Session Key)</strong> (该Session Key用在将来Client与Server Service的通信(会话)上),通过<strong>Client/TGS会话密钥(Client/TGS Session Key)</strong> 进行加密。</li></ul></li><li><p>Client收到这些消息后,用“Client/TGS会话密钥”(Client/TGS Session Key)解密消息F,得到“Client/SS会话密钥”(Client/Server Session Key)。(注意:Client不能解密消息E,因为E是用“服务器密钥”(service’s secret key)加密的)。</p></li></ol><h5 id="2-2-3-服务请求"><a href="#2-2-3-服务请求" class="headerlink" title="2.2.3 服务请求"></a>2.2.3 服务请求</h5><blockquote><p>Client从SS获取服务。</p></blockquote><ol><li>当获得“Client/SS会话密钥”(Client/Server Session Key)之后,Client就能够使用服务器提供的服务了。Client向指定服务器SS发出2条消息:<ul><li>【消息e】:即上一步中的消息E“client-server票据”(client-to-server ticket),通过<strong>服务器密钥(service’s secret key)</strong> 进行加密</li><li>【消息g】:新的<strong>Authenticator</strong>(包括:用户ID,时间戳),通过<strong>Client/SS会话密钥(Client/Server Session Key)</strong> 进行加密</li></ul></li><li><p>SS用自己的密钥(service’s secret key)解密消息e从而得到TGS提供的Client/SS会话密钥(Client/Server Session Key)。再用这个会话密钥解密消息g得到Authenticator,(同TGS一样)对Ticket和Authenticator进行验证,验证通过则返回1条消息(确认函:确证身份真实,乐于提供服务)。</p><ul><li>【消息H】:<strong>新时间戳</strong>(新时间戳是:Client发送的时间戳加1,v5已经取消这一做法),通过<strong>Client/SS会话密钥(Client/Server Session Key)</strong> 进行加密。</li></ul></li><li><p>Client通过Client/SS会话密钥(Client/Server Session Key)解密消息H,得到新时间戳并验证其是否正确。验证通过的话则客户端可以信赖服务器,并向服务器(SS)发送服务请求。</p></li><li><p>服务器(SS)向客户端提供相应的服务。</p></li></ol><h3 id="3-Kerberos-HA架构"><a href="#3-Kerberos-HA架构" class="headerlink" title="3.Kerberos HA架构"></a>3.Kerberos HA架构</h3><p>Kerberos支持两种服务器在域内冗余方式:<code>Master/Slave</code>(MIT和Heimdal)和<code>Multimaster</code>结构(Windows Active Directory)。在生产环境中部署Kerberos时,最好使用一主(Master)多从(Slave)的架构,以确保Kerberos服务的高可用性。</p><p>Kerberos中每个KDC都包含数据库的副本。主KDC包含域(Realm)数据库的<strong>可写副本</strong>,它以固定的时间间隔复制到从KDC中。所有数据库更改(例如密码更改)都在主KDC上进行,当主KDC不可用时,从KDC提供Kerberos票据给服务授权,但不提供数据库管理。KDC需要一个Admin来进行日常的管理操作。</p><p>Kerberos的同步机制只复制主数据库的内容,但不传递配置文件,以下文件必须手动复制到每个Slave中:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">- krb5.conf</span><br><span class="line">- kdc.conf</span><br><span class="line">- kadm5.acl</span><br><span class="line">- master key stash file</span><br></pre></td></tr></table></figure></p><h4 id="3-1-HA方案"><a href="#3-1-HA方案" class="headerlink" title="3.1 HA方案"></a>3.1 HA方案</h4><p>目前单机房HA方案使用的较多的是Keepalived + Rsync 。Keepalived可以将多个无状态的单点通过虚拟IP(以下称为VIP)漂移的方式搭建成一个高可用服务。</p><p>首先,在Master KDC中创建数据库的dump文件(将当前的Kerberos和KADM5数据库转储为ASCII文件):<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kdb5_util dump [-b7|-ov|-r13] [-verbose] [-mkey_convert] [-new_mkey_file mkey_file] [-rev] [-recurse] [filename [principals...]]</span><br></pre></td></tr></table></figure></p><p>然后使用Rsync将目录同步到Slave机器的对应目录中,<br>再导入KDC中:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kdb5_util load [-b7|-ov|-r13] [-hash] [-verbose] [-update] filename [dbname]</span><br></pre></td></tr></table></figure></p><p>Hadoop所有请求通过请求内网域名,解析到Keepalived绑定的VIP的方式来使用KDC:<br><img src="https://s1.ax1x.com/2018/11/03/i4TRJI.png" alt="Kerberos HA"></p><h3 id="4-优化和展望"><a href="#4-优化和展望" class="headerlink" title="4. 优化和展望"></a>4. 优化和展望</h3><h4 id="4-1-优化"><a href="#4-1-优化" class="headerlink" title="4.1 优化"></a>4.1 优化</h4><h6 id="(1)用户(Principal)管理"><a href="#(1)用户(Principal)管理" class="headerlink" title="(1)用户(Principal)管理"></a>(1)用户(Principal)管理</h6><p>如果团队中已经有一套权限系统,要将现有的身份系统集成到Kerberos中会很困难。<br>随着业务的飞速增长,服务器规模越来越大,Kerberos Principal手动操作会越来越频繁,手动的增删改查维护会非常痛苦。需要在Kerberos管理系统中规范Principal申请、维护、删除、keytab生成流程。Principal申请和权限管理自动化。</p><h5 id="(2)数据同步优化"><a href="#(2)数据同步优化" class="headerlink" title="(2)数据同步优化"></a>(2)数据同步优化</h5><p>Kerberos数据同步可以将生成的数据记录同步写入到MySQL中,使用MySQL双主同步方式。在跨机房环境中,KDC数据使用Rsync工具进行增量同步。以A核心机房作为主机房,Rsync Server使用了Keepalived VIP的方式,当Kerberos主机宕机后,VIP漂移到另外一台主机器上,Rsync Client会以VIP所在的KDC主机器为Rsync Server进行数据同步,以保证KDC数据同步的高可用性。</p><h5 id="(3)运维"><a href="#(3)运维" class="headerlink" title="(3)运维"></a>(3)运维</h5><p>使用进程管理工具对Kerberos相关进程进行存活监控,当发现有进程异常退出时,邮件/微信/钉钉报警,主动再次拉起进程。</p><h4 id="4-2-展望"><a href="#4-2-展望" class="headerlink" title="4.2 展望"></a>4.2 展望</h4><p>部署过Kerberos的同学都知道,在Hadoop集群部署Kerberos实际是一项非常繁琐的工作。Kerberos本质上是一种协议或安全通道,对于大多数用户或普通用户来说,是有一定学习曲线的,是否有更好的实现能够对普通用户隐藏这些繁琐的细节。</p><p>阿里和Intel合作项目Hadoop Authentication Service (HAS) 据称目前已经应用到ApsaraDB for HBase2.0中:<br><img src="https://s1.ax1x.com/2018/11/03/i4H9jf.png" alt="HAS"></p><p>HAS方案使用Kerby替代MIT Kerberos服务,利用HAS插件式验证方式建立一套人们习惯的账户密码体系。</p><p>目前HAS在Apache Kerby项目<code>has-project</code>分支开发中,未来会作为Kerbby的新feature出现在下一次release中。</p><p>Apache Kerby作为Apache Directory的一个子项目,目前关注度并不高,让我们期待它在后续的发展吧。</p>]]></content>
<summary type="html">
<h3 id="1-背景"><a href="#1-背景" class="headerlink" title="1.背景"></a>1.背景</h3><p>互联网从来就不是一个安全的地方。很多时候我们过分依赖防火墙来解决安全的问题,不幸的是,防火墙是假设“坏人”是来自外部的,而真正具有破坏性的攻击事件都是往往都是来自于内部的。</p>
<p>近几年,在<code>thehackernews</code>等网站上总会时不时的看到可以看到一些因为数据安全问题被大面积攻击、勒索的事件。在Hadoop1.0.0之前,Hadoop并不提供对安全的支持,默认集群内所有角色都是可靠的。用户访问时不需要进行任何验证,导致恶意用户很容易就可以伪装进入集群进行破坏。<br>
</summary>
<category term="BigData" scheme="http://mantoudev.com/categories/BigData/"/>
<category term="安全" scheme="http://mantoudev.com/categories/BigData/%E5%AE%89%E5%85%A8/"/>
<category term="大数据安全" scheme="http://mantoudev.com/tags/%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%AE%89%E5%85%A8/"/>
<category term="Keberos" scheme="http://mantoudev.com/tags/Keberos/"/>
</entry>
<entry>
<title>[大数据安全]CDH集群禁用Kerberos</title>
<link href="http://mantoudev.com/%5B%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%AE%89%E5%85%A8%5DCDH%E9%9B%86%E7%BE%A4%E7%A6%81%E7%94%A8Kerberos/"/>
<id>http://mantoudev.com/[大数据安全]CDH集群禁用Kerberos/</id>
<published>2018-11-20T13:39:40.000Z</published>
<updated>2018-11-27T14:33:29.831Z</updated>
<content type="html"><![CDATA[<blockquote><p>在调试Kerberos的时候可能会有需要禁用的场景。以下是各组件禁用Kerberos的相关配置。</p></blockquote><h3 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h3><ul><li>CDH版本:5.11.2 </li><li>Linux版本:7.4.1708</li><li>Docker版本:Docker version 18.06.0-ce</li><li>JDK版本:1.8<a id="more"></a></li></ul><h3 id="Zookeeper"><a href="#Zookeeper" class="headerlink" title="Zookeeper"></a>Zookeeper</h3><ul><li><code>enableSecurity (Enable Kerberos Authentication)</code> : false</li><li><code>zoo.cfg</code> 的Server 高级配置代码段(安全阀)写入skipACL: yes</li></ul><h3 id="HDFS"><a href="#HDFS" class="headerlink" title="HDFS"></a>HDFS</h3><ul><li><code>hadoop.security.authentication</code> : Simple</li><li><code>hadoop.security.authorization</code> : false</li><li><code>dfs.datanode.address</code> : 1004 (for Kerberos) 改为 50010 (default)</li><li><code>dfs.datanode.http.address</code> : 1006 (for Kerberos) 改为 50075 (default)</li><li><code>dfs.datanode.data.dir.perm</code> : 700 改为 755</li></ul><h3 id="HBase"><a href="#HBase" class="headerlink" title="HBase"></a>HBase</h3><ul><li><code>hbase.security.authentication</code> : Simple</li><li><code>hbase.security.authorization</code> : false</li><li><code>hbase.thrift.security.qop</code> : none</li></ul><h3 id="Hue"><a href="#Hue" class="headerlink" title="Hue"></a>Hue</h3><ul><li><code>Kerberos Ticket Renewer</code>: 删除或停用角色</li></ul><h3 id="Kafka"><a href="#Kafka" class="headerlink" title="Kafka"></a>Kafka</h3><ul><li><code>kerberos.auth.enable</code>: false</li></ul><h3 id="SOLR"><a href="#SOLR" class="headerlink" title="SOLR"></a>SOLR</h3><ul><li><code>solr Secure Authentication</code> : Simple</li></ul><hr><p>参考资料:<br> [1]Cloudera Manager Community : <a href="http://community.cloudera.com/t5/Cloudera-Manager-Installation/Disabling-Kerberos/td-p/19654" target="_blank" rel="noopener">http://community.cloudera.com/t5/Cloudera-Manager-Installation/Disabling-Kerberos/td-p/19654</a></p>]]></content>
<summary type="html">
<blockquote>
<p>在调试Kerberos的时候可能会有需要禁用的场景。以下是各组件禁用Kerberos的相关配置。</p>
</blockquote>
<h3 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h3><ul>
<li>CDH版本:5.11.2 </li>
<li>Linux版本:7.4.1708</li>
<li>Docker版本:Docker version 18.06.0-ce</li>
<li>JDK版本:1.8
</summary>
<category term="BigData" scheme="http://mantoudev.com/categories/BigData/"/>
<category term="安全" scheme="http://mantoudev.com/categories/BigData/%E5%AE%89%E5%85%A8/"/>
<category term="Kerberos" scheme="http://mantoudev.com/tags/Kerberos/"/>
<category term="大数据安全" scheme="http://mantoudev.com/tags/%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%AE%89%E5%85%A8/"/>
</entry>
<entry>
<title>[大数据安全]Kerberos集群安装配置</title>
<link href="http://mantoudev.com/%5B%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%AE%89%E5%85%A8%5DKerberos%E9%9B%86%E7%BE%A4%E5%AE%89%E8%A3%85%E9%85%8D%E7%BD%AE/"/>
<id>http://mantoudev.com/[大数据安全]Kerberos集群安装配置/</id>
<published>2018-11-16T13:39:40.000Z</published>
<updated>2018-11-27T14:33:34.661Z</updated>
<content type="html"><![CDATA[<h2 id="1-概述"><a href="#1-概述" class="headerlink" title="1. 概述"></a>1. 概述</h2><p>Kerberos是一种计算机网络认证协议,它允许某实体在非安全网络环境下通信,向另一个实体以一种安全的方式证明自己的身份。它也指由麻省理工实现此协议,并发布的一套免费软件。它的设计主要针对客户-服务器模型,并提供了一系列交互认证——用户和服务器都能验证对方的身份。Kerberos协议可以保护网络实体免受窃听和重复攻击。<br><a id="more"></a></p><p>Kerberos协议基于对称密码学,并需要一个值得信赖的第三方。Kerberos协议的扩展可以为认证的某些阶段提供公钥密码学支持。</p><h2 id="2-环境说明:"><a href="#2-环境说明:" class="headerlink" title="2. 环境说明:"></a>2. 环境说明:</h2><ul><li>CDH版本:5.11.2</li><li>Linux版本:Centos 7</li><li>Docker版本:Docker version 18.06.0-ce</li><li>JDK版本:1.8</li><li>操作用户:root</li></ul><p>机器部署:</p><table><thead><tr><th>#</th><th>IP</th><th>主机名</th><th>Server</th><th>Client</th></tr></thead><tbody><tr><td>1</td><td>192.168.101.232</td><td>cdh-server-1</td><td>N/A</td><td>Kerberos client</td></tr><tr><td>2</td><td>192.168.101.233</td><td>cdh-node-1</td><td>Kerberos server</td><td>N/A</td></tr><tr><td>3</td><td>192.168.101.234</td><td>cdh-node-2</td><td>N/A</td><td>Kerberos client</td></tr><tr><td>4</td><td>192.168.101.235</td><td>cdh-node-3</td><td>N/A</td><td>Kerberos client</td></tr></tbody></table><p>各节点之间可以通过ssh免密码登录<br>Kerberos服务器和客户之间的时间同步</p><h2 id="3-Kerberos-安装"><a href="#3-Kerberos-安装" class="headerlink" title="3. Kerberos 安装"></a>3. Kerberos 安装</h2><p><code>cdh-node-1</code>作为Kerberos主节点安装服务:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install krb5-libs krb5-server krb5-workstation</span><br></pre></td></tr></table></figure></p><p>通过命令查看安装列表<code>rpm -qa|grep krb5</code>:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-1 /]# rpm -qa | grep krb5</span><br><span class="line">krb5-workstation-1.15.1-19.el7.x86_64</span><br><span class="line">krb5-devel-1.15.1-19.el7.x86_64</span><br><span class="line">krb5-server-1.15.1-19.el7.x86_64</span><br><span class="line">krb5-libs-1.15.1-19.el7.x86_64</span><br><span class="line">[root@cdh-node-1 /]#</span><br></pre></td></tr></table></figure><h2 id="4-配置"><a href="#4-配置" class="headerlink" title="4. 配置"></a>4. 配置</h2><p>kdc服务器包含三个配置文件:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"># 集群上所有节点都有这个文件而且内容同步</span><br><span class="line">/etc/krb5.conf</span><br><span class="line"># 主服务器上的kdc配置</span><br><span class="line">/var/kerberos/krb5kdc/kdc.conf</span><br><span class="line"># 能够不直接访问 KDC 控制台而从 Kerberos 数据库添加和删除主体,需要添加配置</span><br><span class="line">/var/kerberos/krb5kdc/kadm5.acl</span><br></pre></td></tr></table></figure></p><p><strong>1. 首先配置<code>/etc/krb5.conf</code>文件:</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">[logging]</span><br><span class="line"> default = FILE:/var/log/krb5libs.log</span><br><span class="line"> kdc = FILE:/var/log/krb5kdc.log</span><br><span class="line"> admin_server = FILE:/var/log/kadmind.log</span><br><span class="line"></span><br><span class="line">[libdefaults]</span><br><span class="line"> default_realm = EXAMPLE.COM #此处需要进行配置,把默认的EXAMPLE.COM修改为自己要定义的值</span><br><span class="line"> dns_lookup_kdc = false</span><br><span class="line"> dns_lookup_realm = false</span><br><span class="line"> ticket_lifetime = 24h</span><br><span class="line"> renew_lifetime = 7d</span><br><span class="line"> forwardable = true</span><br><span class="line"> default_tgs_enctypes = rc4-hmac</span><br><span class="line"> default_tkt_enctypes = rc4-hmac</span><br><span class="line"> permitted_enctypes = rc4-hmac</span><br><span class="line"> udp_preference_limit = 1</span><br><span class="line"> kdc_timeout = 3000</span><br><span class="line"></span><br><span class="line">[realms]</span><br><span class="line"> EXAMPLE.COM = {</span><br><span class="line"> kdc = cdh-node-1 #此处配置的为主机名</span><br><span class="line"> admin_server = cdh-node-1 #同上</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></p><p><strong>配置项说明:</strong><br>更多参数设置请参考:<a href="http://web.mit.edu/kerberos/krb5-latest/doc/admin/conf_files/krb5_conf.html?highlight=rdns" target="_blank" rel="noopener">官方文档。</a></p><p>以下是几个核心参数的说明:</p><ul><li><code>[logging]</code>:日志输出设置 (可选) </li><li><p><code>[libdefaults]</code>:连接的默认配置</p><ul><li><code>default_realm</code>:Kerberos应用程序的默认领域,所有的principal都将带有这个领域标志</li><li><code>ticket_lifetime</code>: 表明凭证生效的时限,一般为24小时</li><li><code>renew_lifetime</code>: 表明凭证最长可以被延期的时限,一般为一个礼拜。当凭证过期之后,对安全认证的服务的后续访问则会失败</li><li><code>clockskew</code>:时钟偏差是不完全符合主机系统时钟的票据时戳的容差,超过此容差将不接受此票据。通常,将时钟扭斜设置为 300 秒(5 分钟)。这意味着从服务器的角度看,票证的时间戳与它的偏差可以是在前后 5 分钟内</li><li><code>udp_preference_limit= 1</code>:禁止使用 udp 可以防止一个 Hadoop 中的错误</li><li><code>default_ccache_name</code>:credential缓存名,默认值为</li></ul></li><li><p><code>[realms]</code>:列举使用的 realm</p><ul><li><code>kdc</code>:代表要 kdc 的位置。格式是 机器:端口</li><li><code>admin_server</code>:代表 admin 的位置。格式是 机器:端口</li><li><code>default_domain</code>:代表默认的域名</li></ul></li><li><p><code>[domain_realm]</code>:域名到realm的关系 (可选)</p></li></ul><p><strong>2.配置<code>/var/kerberos/krb5kdc/kdc.conf</code>文件</strong></p><blockquote><p>此处为EXAMPLE.COM与/etc/krb5.conf中的配置保持一致。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">[kdcdefaults]</span><br><span class="line"> kdc_ports = 88</span><br><span class="line"> kdc_tcp_ports = 88</span><br><span class="line"></span><br><span class="line">[realms]</span><br><span class="line"> EXAMPLE.COM = {</span><br><span class="line"> #master_key_type = aes256-cts</span><br><span class="line"> acl_file = /var/kerberos/krb5kdc/kadm5.acl</span><br><span class="line"> dict_file = /usr/share/dict/words</span><br><span class="line"> admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab</span><br><span class="line"> supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal</span><br><span class="line"> max_life = 1d</span><br><span class="line"> max_renewable_life = 7d</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></p></blockquote><p>配置项说明:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">- `kdcdefaults`:kdc相关配置,这里只设置了端口信息</span><br><span class="line">- `realms`:realms的配置</span><br><span class="line"> - `EXAMPLE.COM`:设定的realms领域</span><br><span class="line"> - `master_key_type`:和 supported_enctypes 默认使用 aes256-cts。JAVA 使用 aes256-cts 验证方式需要安装 JCE包(推荐不使用)</span><br><span class="line"> - `acl_file`:标注了 admin 的用户权限,文件格式是:Kerberos_principal permissions [target_principal] [restrictions]</span><br><span class="line"> - `supported_enctypes`:支持的校验方式</span><br><span class="line"> - `admin_keytab`:KDC 进行校验的 keytab</span><br></pre></td></tr></table></figure></p><blockquote><p><strong>关于<code>AES-256</code>加密</strong>:<br>对于使用 Centos5.6 及以上的系统,默认使用 <code>AES-256</code>来加密的。这就需要集群中的所有节点上安装 <a href="http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html" target="_blank" rel="noopener">Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy File</a><br>下载的文件是一个 zip 包,解开后,将里面的两个文件放到下面的目录中:<code>$JAVA_HOME/jre/lib/security</code></p></blockquote><p><strong>3. 创建<code>/var/kerberos/krb5kdc/kadm5.acl</code></strong><br>内容为:<a href="mailto:`*/[email protected]" target="_blank" rel="noopener">`*/[email protected]</a> <em><code>代表名称匹配</code>/admin@EXAMPLE COM` 都认为是admin,权限是 </em> 代表全部权限。<br>在KDC上我们需要编辑acl文件来设置权限,该acl文件的默认路径是 <code>/var/kerberos/krb5kdc/kadm5.acl</code>(也可以在文件kdc.conf中修改)。</p><p>Kerberos的kadmind daemon会使用该文件来管理对Kerberos database的访问权限。对于那些可能会对pincipal产生影响的操作,acl文件也能控制哪些principal能操作哪些其他pricipals。</p><p><strong>4. 创建Kerberos数据库</strong><br>此步可能用时较长,创建完成会在<code>/var/kerberos/krb5kdc/</code>下面生成一系列文件。并且会提示输入数据库管理员的密码。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/usr/sbin/kdb5_util create -r EXAMPLE.COM –s # 此处为EXAMPLE.COM与/etc/krb5.conf中的配置保持一致。</span><br></pre></td></tr></table></figure></p><ul><li><code>[-s]</code>:表示生成stash file,并在其中存储master server key(krb5kdc);</li><li><code>[-r]</code>:指定一个realm name —— 当krb5.conf中定义了多个realm时才是必要的。</li></ul><p>如果需要重建数据库,将<code>/var/kerberos/krb5kdc</code>目录下的principal相关的文件删除即可.</p><p>当Kerberos database创建好后,可以看到目录 <code>/var/kerberos/krb5kdc</code> 下生成了几个文件:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">kadm5.acl</span><br><span class="line">kdc.conf</span><br><span class="line">principal</span><br><span class="line">principal.kadm5</span><br><span class="line">principal.kadm5.lock</span><br><span class="line">principal.ok</span><br></pre></td></tr></table></figure><p><strong>5. 添加database administrator</strong><br>为Kerberos database添加administrative principals (即能够管理database的principals) —— 至少要添加1个principal来使得Kerberos的管理进程kadmind能够在网络上与程序kadmin进行通讯。</p><p>创建管理员并输入密码<code>admin</code>。kadmin.local可以直接运行在KDC上,而无需通过Kerberos认证。</p><p>为用户设置密码:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-1 /]# kadmin.local -q "addprinc admin/admin"</span><br><span class="line">Authenticating as principal root/[email protected] with password.</span><br><span class="line">WARNING: no policy specified for admin/[email protected]; defaulting to no policy</span><br><span class="line">Enter password for principal "admin/[email protected]":</span><br><span class="line">Re-enter password for principal "admin/[email protected]": </span><br><span class="line">Principal "admin/[email protected]" created.</span><br></pre></td></tr></table></figure><p><strong>6. 设置kerberos服务为开机启动,关闭防火墙</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">chkconfig krb5kdc on</span><br><span class="line">chkconfig kadmin on</span><br><span class="line">chkconfig iptables off</span><br></pre></td></tr></table></figure></p><p><strong>7. 启动krb5kdc和kadmind进程</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">/usr/sbin/kadmind</span><br><span class="line">/usr/sbin/krb5kdc</span><br></pre></td></tr></table></figure></p><p>或<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">service krb5kdc start</span><br><span class="line">service kadmin start</span><br><span class="line">service krb5kdc status</span><br></pre></td></tr></table></figure></p><p>现在KDC已经在工作了。这两个daemons将会在后台运行,可以查看它们的日志文件(<code>/var/log/krb5kdc.log 和 /var/log/kadmind.log</code>)。</p><p><strong>8. 检查Kerberos正常运行</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kinit admin/admin</span><br></pre></td></tr></table></figure></p><p><strong>9. 集群中的其他主机安装Kerberos Client</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install krb5-workstation krb5-libs krb5-auth-dialog</span><br></pre></td></tr></table></figure></p><p>配置这些主机上的<code>/etc/krb5.conf</code>,这个文件的内容与KDC中的文件保持一致即可。 </p><p><strong>10. 在cm节点安装ldap客户端</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install openldap-clients</span><br></pre></td></tr></table></figure></p><h2 id="5-Kerberos使用"><a href="#5-Kerberos使用" class="headerlink" title="5. Kerberos使用"></a>5. Kerberos使用</h2><p>常用命令:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">kinit admin/[email protected] # 初始化证书</span><br><span class="line">klist # 查看当前证书</span><br><span class="line">kadmin.local -q "list_principals" # 列出Kerberos中的所有认证用户</span><br><span class="line">kadmin.local -q "addprinc user1" # 添加认证用户,需要输入密码</span><br><span class="line">kinit user1 # 使用该用户登录,获取身份认证,需要输入密码</span><br><span class="line">klist # 查看当前用户的认证信息ticket</span><br><span class="line">kinit –R # 更新ticket</span><br><span class="line">kdestroy # 销毁当前的ticket</span><br><span class="line">kadmin.local -q "delprinc user1" # 删除认证用户</span><br></pre></td></tr></table></figure><h3 id="5-1-管理员使用"><a href="#5-1-管理员使用" class="headerlink" title="5.1 管理员使用"></a>5.1 管理员使用</h3><p><strong>1. 登录</strong><br>登录到管理员账户,如果在本机上,可以通过kadmin.local直接登录:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-1 /]# kadmin.local</span><br><span class="line">Authenticating as principal root/[email protected] with password.</span><br><span class="line">kadmin.local:</span><br></pre></td></tr></table></figure><p>其它机器的,先使用kinit进行验证:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-server-1 /]# kinit admin/admin</span><br><span class="line">Password for admin/[email protected]:</span><br><span class="line">[root@cdh-server-1 /]# kadmin</span><br><span class="line">Authenticating as principal admin/[email protected] with password.</span><br><span class="line">Password for admin/[email protected]:</span><br><span class="line">kadmin:</span><br></pre></td></tr></table></figure><p><strong>2. 增删改查账户</strong><br>在管理员的状态下使用<code>addprinc</code>,<code>delprinc</code>,<code>modprinc</code>,<code>listprincs</code>命令。使用<code>?</code>可以列出所有的命令。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-1 /]# kadmin.local</span><br><span class="line">Authenticating as principal root/[email protected] with password.</span><br><span class="line">kadmin.local: delprinc test</span><br><span class="line">Are you sure you want to delete the principal "[email protected]"? (yes/no): yes</span><br><span class="line">Principal "[email protected]" deleted.</span><br><span class="line">Make sure that you have removed this principal from all ACLs before reusing.</span><br><span class="line">kadmin.local: listprincs</span><br><span class="line">HTTP/[email protected]</span><br><span class="line">HTTP/[email protected]</span><br><span class="line">HTTP/[email protected]</span><br><span class="line">...</span><br></pre></td></tr></table></figure></p><p><strong>3. 生成keytab:使用<code>xst</code>命令或者<code>ktadd</code>命令</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-1 /]# kadmin:xst -k /xxx/xxx/kerberos.keytab hdfs/hadoop1</span><br></pre></td></tr></table></figure></p><h3 id="5-2-用户使用"><a href="#5-2-用户使用" class="headerlink" title="5.2 用户使用"></a>5.2 用户使用</h3><p><strong>1. 查看当前认证用户</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-2 /]# klist</span><br><span class="line">Ticket cache: FILE:/tmp/krb5cc_0</span><br><span class="line">Default principal: [email protected]</span><br><span class="line"></span><br><span class="line">Valid starting Expires Service principal</span><br><span class="line">08/08/2018 17:49:41 08/09/2018 17:49:41 krbtgt/[email protected]</span><br></pre></td></tr></table></figure></p><p><strong>2. 认证用户</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-2 /]# kinit -kt /xx/xx/kerberos.keytab hdfs/hadoop1</span><br></pre></td></tr></table></figure></p><p><strong>3. 删除当前的认证的缓存</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-2 /]# kdestroy</span><br><span class="line">[root@cdh-node-2 /]# klist</span><br><span class="line">klist: No credentials cache found (filename: /tmp/krb5cc_0)</span><br></pre></td></tr></table></figure></p><h2 id="6-一些概念"><a href="#6-一些概念" class="headerlink" title="6. 一些概念"></a>6. 一些概念</h2><h4 id="1-Principal"><a href="#1-Principal" class="headerlink" title="1. Principal"></a>1. Principal</h4><p>Kerberos principal用于在kerberos加密系统中标记一个唯一的身份。<br>kerberos为kerberos principal分配tickets使其可以访问由kerberos加密的hadoop服务。<br>对于hadoop,principals的格式为<a href="mailto:username/[email protected]" target="_blank" rel="noopener">username/[email protected]</a>.</p><h4 id="2-Keytab"><a href="#2-Keytab" class="headerlink" title="2. Keytab"></a>2. Keytab</h4><p>keytab是包含principals和加密principal key的文件。<br>keytab文件对于每个host是唯一的,因为key中包含hostname。keytab文件用于不需要人工交互和保存纯文本密码,实现到kerberos上验证一个主机上的principal。<br>因为服务器上可以访问keytab文件即可以以principal的身份通过kerberos的认证,所以,keytab文件应该被妥善保存,应该只有少数的用户可以访问。</p>]]></content>
<summary type="html">
<h2 id="1-概述"><a href="#1-概述" class="headerlink" title="1. 概述"></a>1. 概述</h2><p>Kerberos是一种计算机网络认证协议,它允许某实体在非安全网络环境下通信,向另一个实体以一种安全的方式证明自己的身份。它也指由麻省理工实现此协议,并发布的一套免费软件。它的设计主要针对客户-服务器模型,并提供了一系列交互认证——用户和服务器都能验证对方的身份。Kerberos协议可以保护网络实体免受窃听和重复攻击。<br>
</summary>
<category term="BigData" scheme="http://mantoudev.com/categories/BigData/"/>
<category term="安全" scheme="http://mantoudev.com/categories/BigData/%E5%AE%89%E5%85%A8/"/>
<category term="Kerberos" scheme="http://mantoudev.com/tags/Kerberos/"/>
<category term="大数据安全" scheme="http://mantoudev.com/tags/%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%AE%89%E5%85%A8/"/>
</entry>
<entry>
<title>[大数据安全]Apache Kylin 安全配置(Kerberos)</title>
<link href="http://mantoudev.com/%5B%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%AE%89%E5%85%A8%5DApache%20Kylin%20%E5%AE%89%E5%85%A8%E9%85%8D%E7%BD%AE(Kerberos)/"/>
<id>http://mantoudev.com/[大数据安全]Apache Kylin 安全配置(Kerberos)/</id>
<published>2018-11-15T13:39:40.000Z</published>
<updated>2018-11-28T16:04:37.709Z</updated>
<content type="html"><![CDATA[<h2 id="1-概述"><a href="#1-概述" class="headerlink" title="1. 概述"></a>1. 概述</h2><p>本文首先会简单介绍Kylin的安装配置,然后介绍启用Kerberos的CDH集群中如何部署及使用Kylin。</p><p>Apache Kylin™是一个开源的分布式分析引擎,提供Hadoop/Spark之上的SQL查询接口及多维分析(OLAP)能力以支持超大规模数据,最初由eBay Inc. 开发并贡献至开源社区。它能在亚秒内查询巨大的Hive表。<br><a id="more"></a></p><p><img src="http://kylin.apache.org/assets/images/kylin_diagram.png" alt="image"></p><h4 id="1-2-环境说明"><a href="#1-2-环境说明" class="headerlink" title="1.2 环境说明"></a>1.2 环境说明</h4><ul><li>CDH版本:5.11.2</li><li>Linux版本:7.4.1708</li><li>Docker版本:Docker version 18.06.0-ce</li><li>JDK版本:1.8</li><li>操作用户:root</li></ul><h2 id="2-Kylin安装配置"><a href="#2-Kylin安装配置" class="headerlink" title="2.Kylin安装配置"></a>2.Kylin安装配置</h2><h3 id="2-1-安装"><a href="#2-1-安装" class="headerlink" title="2.1 安装"></a>2.1 安装</h3><p>此处以Kylin 2.0.0版本为例。<br>社区版Kylin地址:<a href="https://archive.apache.org/dist/kylin/" target="_blank" rel="noopener">https://archive.apache.org/dist/kylin/</a></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[root@node-3 ~]# cd /usr/local/src/</span><br><span class="line">[root@node-3 src]# wget https://archive.apache.org/dist/kylin/apache-kylin-2.0.0/apache-kylin-2.0.0-bin-cdh57.tar.gz</span><br><span class="line">[root@node-3 src]# tar xf apache-kylin-2.0.0-bin-cdh57.tar.gz</span><br><span class="line">[root@node-3 src]# cp -a apache-kylin-2.0.0-bin /usr/local/</span><br><span class="line">[root@node-3 src]# ln -s /usr/local/apache-kylin-2.0.0-bin /usr/local/kylin</span><br></pre></td></tr></table></figure><h3 id="2-2-环境配置"><a href="#2-2-环境配置" class="headerlink" title="2.2 环境配置"></a>2.2 环境配置</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">export BASE_PATH_BIG=/opt/cloudera/parcels/CDH/lib</span><br><span class="line"></span><br><span class="line">#added by Hbase</span><br><span class="line">export HBASE_HOME=$BASE_PATH_BIG/hbase</span><br><span class="line"></span><br><span class="line">#added by HCat</span><br><span class="line">export HCAT_HOME=/opt/cloudera/parcels/CDH/lib/hive-hcatalog/share/hcatalog</span><br><span class="line"></span><br><span class="line">#added by Kylin</span><br><span class="line">export KYLIN_HOME=/usr/local/kylin</span><br><span class="line">export PATH=$HBASE_HOME/bin:$PATH</span><br></pre></td></tr></table></figure><p>然后执行<code>source /etc/profile</code>生效。</p><h3 id="2-3-Kylin配置"><a href="#2-3-Kylin配置" class="headerlink" title="2.3 Kylin配置"></a>2.3 Kylin配置</h3><p>编辑<code>/usr/local/kylin/conf/kylin.properites</code>文件,新增以下配置:</p><blockquote><p>Kylin2.0+版本配置的名称有变化,具体参考:<a href="https://github.com/apache/kylin/blob/2.0.x/core-common/src/main/resources/kylin-backward-compatibility.properties" target="_blank" rel="noopener">https://github.com/apache/kylin/blob/2.0.x/core-common/src/main/resources/kylin-backward-compatibility.properties</a></p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">## 修改配置(替换地址)</span><br><span class="line">kylin.rest.servers=192.168.100.102:7070</span><br><span class="line"></span><br><span class="line">## 新增配置</span><br><span class="line">kylin.job.jar=/usr/local/apache-kylin-2.0.0-bin/lib/kylin-job-2.0.0.jar</span><br><span class="line">kylin.coprocessor.local.jar=/usr/local/apache-kylin-2.0.0-bin/lib/kylin-coprocessor-2.0.0.jar</span><br><span class="line">## 替换地址</span><br><span class="line">kylin.job.yarn.app.rest.check.status.url=http://cdh-node-2:8088/ws/v1/cluster/apps/${job_id}?anonymous=true</span><br><span class="line">kylin.job.mr.lib.dir=/opt/cloudera/parcels/CDH-5.11.2-1.cdh5.11.2.p0.4/lib/sentry/lib</span><br></pre></td></tr></table></figure><h5 id="配置说明:"><a href="#配置说明:" class="headerlink" title="配置说明:"></a>配置说明:</h5><ul><li><p><code>kylin.rest.servers</code>:kylin实例服务器列表,注意:不包括以job模式运行的服务器实例!</p></li><li><p><code>kylin.job.jar</code>:MR jobs依赖</p></li><li><code>kylin.coprocessor.local.jar</code>:Hbase协同处理依赖,用于提高性能。</li><li><code>kylin.job.yarn.app.rest.check.status.url</code>:yarn工作区</li><li><code>kylin.job.mr.lib.dir</code>:Hive/Hbase依赖目录。(在没有安装Hive/Hbase的节点上构建Cube会因为找不到依赖报ClassNotFoundException错误,需要此配置。具体参考这边博文<a href="http://www.whitewood.me/2017/11/04/Kylin%E5%AE%9E%E6%88%98%EF%BC%88%E5%85%AD%EF%BC%89%EF%BC%9A%E4%B8%8A%E4%BC%A0Kylin%20MR%E4%BE%9D%E8%B5%96/" target="_blank" rel="noopener">《上传Kylin MR依赖》</a>)。</li></ul><p>更多配置请参考<a href="http://kylin.apache.org/cn/docs/install/configuration.html" target="_blank" rel="noopener">官网配置指南</a>。</p><h3 id="2-4-创建用户"><a href="#2-4-创建用户" class="headerlink" title="2.4 创建用户"></a>2.4 创建用户</h3><p>在每个节点创建Kylin用户</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">useradd kylin</span><br></pre></td></tr></table></figure><h2 id="3-Kerberos配置"><a href="#3-Kerberos配置" class="headerlink" title="3. Kerberos配置"></a>3. Kerberos配置</h2><h3 id="3-1-创建kylin账号"><a href="#3-1-创建kylin账号" class="headerlink" title="3.1 创建kylin账号"></a>3.1 创建kylin账号</h3><p>在Kerberos server上创建kylin账号:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-1 /]# kadmin.local</span><br><span class="line">Authenticating as principal admin/[email protected] with password.</span><br><span class="line">kadmin.local: addprinc kylin</span><br><span class="line">WARNING: no policy specified for [email protected]; defaulting to no policy</span><br><span class="line">Enter password for principal "[email protected]":</span><br><span class="line">Re-enter password for principal "[email protected]":</span><br><span class="line">add_principal: Principal or policy already exists while creating "[email protected]".</span><br><span class="line">kadmin.local:</span><br></pre></td></tr></table></figure><h3 id="3-2-生成keytab文件"><a href="#3-2-生成keytab文件" class="headerlink" title="3.2 生成keytab文件"></a>3.2 生成keytab文件</h3><p>生成kylin账号keytab文件:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xst -norandkey -k kylin.keytab [email protected]</span><br></pre></td></tr></table></figure></p><p>将kylin.keytab复制到每个kylin节点上。</p><h3 id="3-3-定时刷新kt"><a href="#3-3-定时刷新kt" class="headerlink" title="3.3 定时刷新kt"></a>3.3 定时刷新kt</h3><p>在kylin节点上配置定时任务进行<code>kinit</code>命令:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kinit -k -t /root/kylin.keytab [email protected]</span><br></pre></td></tr></table></figure><p>添加定时任务,这里设置每天凌晨1点执行一次,可根据kerberos的过期时间自己配置。</p><ul><li>编写shell脚本:</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-2 security]# cat init_kt.sh</span><br><span class="line">#!/bin/bash</span><br><span class="line">kinit -kt ./kylin.keytab [email protected]</span><br></pre></td></tr></table></figure><ul><li>添加定时任务:</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-2 security]# crontab -e</span><br><span class="line"></span><br><span class="line"># 添加以下内容</span><br><span class="line">0 1 * * * root /home/security/init_kt.sh > /tmp/kylin-ktinit.log 2>&1</span><br><span class="line"></span><br><span class="line"># 查看定时任务</span><br><span class="line">[root@cdh-node-2 security]# crontab -l</span><br><span class="line">0 1 * * * root /home/security/init_kt.sh > /tmp/kylin-ktinit.log 2>&1</span><br></pre></td></tr></table></figure><h3 id="3-4-添加Hive权限"><a href="#3-4-添加Hive权限" class="headerlink" title="3.4 添加Hive权限"></a>3.4 添加Hive权限</h3><ul><li>登录Hive<br>使用拥有操作hive权限的kerberos账户登录beeline:</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-3 hive]# beeline -u 'jdbc:hive2://cdh-node-3:10000/default;principal=hive/[email protected]'</span><br><span class="line">Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=512M; support was removed in 8.0</span><br><span class="line">Java HotSpot(TM) 64-Bit Server VM warning: Using incremental CMS is deprecated and will likely be removed in a future release</span><br><span class="line">Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=512M; support was removed in 8.0</span><br><span class="line">scan complete in 2ms</span><br><span class="line">Connecting to jdbc:hive2://cdh-node-3:10000/default;principal=hive/[email protected]</span><br><span class="line">Connected to: Apache Hive (version 1.1.0-cdh5.11.2)</span><br><span class="line">Driver: Hive JDBC (version 1.1.0-cdh5.11.2)</span><br><span class="line">Transaction isolation: TRANSACTION_REPEATABLE_READ</span><br><span class="line">Beeline version 1.1.0-cdh5.11.2 by Apache Hive</span><br><span class="line">0: jdbc:hive2://cdh-node-3:10000/default></span><br></pre></td></tr></table></figure><ul><li>添加kylin权限<br>将<code>admin</code>角色权限赋予<code>kylin</code>:</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">0: jdbc:hive2://cdh-node-3:10000/default> grant role admin to user kylin;</span><br><span class="line">INFO : Compiling command(queryId=hive_20180914174141_6359e1a1-251f-4116-b646-0aa9f55dcfa8): grant role admin to user leili</span><br><span class="line">INFO : Semantic Analysis Completed</span><br><span class="line">INFO : Returning Hive schema: Schema(fieldSchemas:null, properties:null)</span><br><span class="line">INFO : Completed compiling command(queryId=hive_20180914174141_6359e1a1-251f-4116-b646-0aa9f55dcfa8); Time taken: 0.069 seconds</span><br><span class="line">INFO : Executing command(queryId=hive_20180914174141_6359e1a1-251f-4116-b646-0aa9f55dcfa8): grant role admin to user leili</span><br><span class="line">INFO : Starting task [Stage-0:DDL] in serial mode</span><br><span class="line">INFO : Completed executing command(queryId=hive_20180914174141_6359e1a1-251f-4116-b646-0aa9f55dcfa8); Time taken: 0.331 seconds</span><br><span class="line">INFO : OK</span><br><span class="line">No rows affected (0.528 seconds)</span><br></pre></td></tr></table></figure><h3 id="3-5-添加Hbase权限"><a href="#3-5-添加Hbase权限" class="headerlink" title="3.5 添加Hbase权限"></a>3.5 添加Hbase权限</h3><p>使用拥有操作hbase权限的kerberos账户登录hbase shell:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-3 hive]# hbase shell</span><br><span class="line">Java HotSpot(TM) 64-Bit Server VM warning: Using incremental CMS is deprecated and will likely be removed in a future release</span><br><span class="line">18/09/14 17:44:40 INFO Configuration.deprecation: hadoop.native.lib is deprecated. Instead, use io.native.lib.available</span><br><span class="line">HBase Shell; enter 'help<RETURN>' for list of supported commands.</span><br><span class="line">Type "exit<RETURN>" to leave the HBase Shell</span><br><span class="line">Version 1.2.0-cdh5.11.2, rUnknown, Fri Aug 18 14:09:37 PDT 2017</span><br></pre></td></tr></table></figure><ul><li>给kylin用户授权<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">base(main):001:0> grant 'kylin','RWXCA'</span><br><span class="line">0 row(s) in 0.5830 seconds</span><br></pre></td></tr></table></figure></li></ul><p>切换到kylin用户重新登录hbase shell,测试一下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">hbase(main):001:0> whoami</span><br><span class="line">[email protected] (auth:KERBEROS)</span><br><span class="line"> groups: kylin</span><br><span class="line"></span><br><span class="line">hbase(main):002:0> create 'test', 'cf'</span><br><span class="line">0 row(s) in 2.6930 seconds</span><br><span class="line"></span><br><span class="line">=> Hbase::Table - test</span><br><span class="line">hbase(main):003:0> list</span><br><span class="line">TABLE</span><br><span class="line">test</span><br><span class="line">1 row(s) in 0.0310 seconds</span><br></pre></td></tr></table></figure><h3 id="3-6-执行Kylin检查"><a href="#3-6-执行Kylin检查" class="headerlink" title="3.6 执行Kylin检查"></a>3.6 执行Kylin检查</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-2 bin]# ./check-env.sh</span><br><span class="line">Retrieving hadoop conf dir...</span><br><span class="line">KYLIN_HOME is set to /usr/local/apache-kylin-2.0.0-bin</span><br></pre></td></tr></table></figure><h3 id="3-7-启动kylin服务"><a href="#3-7-启动kylin服务" class="headerlink" title="3.7 启动kylin服务"></a>3.7 启动kylin服务</h3><p>先确认主机使用kerberos凭据为<code>kylin</code>,再启动:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-2 bin]# klist</span><br><span class="line">Ticket cache: FILE:/tmp/krb5cc_0</span><br><span class="line">Default principal: [email protected]</span><br><span class="line"></span><br><span class="line">Valid starting Expires Service principal</span><br><span class="line">09/14/2018 17:48:28 09/15/2018 17:48:28 krbtgt/[email protected]</span><br><span class="line">renew until 09/21/2018 17:48:28</span><br><span class="line">[root@cdh-node-2 bin]# ./kylin.sh start</span><br><span class="line">Retrieving hadoop conf dir...</span><br><span class="line">KYLIN_HOME is set to /usr/local/kylin</span><br><span class="line">Retrieving hive dependency...</span><br><span class="line">Retrieving hbase dependency...</span><br><span class="line">Retrieving hadoop conf dir...</span><br><span class="line">Retrieving kafka dependency...</span><br><span class="line">Retrieving Spark dependency...</span><br><span class="line">KYLIN_JVM_SETTINGS is -Xms1024M -Xmx4096M -Xss1024K -XX:MaxPermSize=128M -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/usr/local/kylin/logs/kylin.gc.3982 -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=64M</span><br><span class="line"></span><br><span class="line">A new Kylin instance is started by root. To stop it, run 'kylin.sh stop'</span><br><span class="line">Check the log at /usr/local/kylin/logs/kylin.log</span><br><span class="line">Web UI is at http://<hostname>:7070/kylin</span><br></pre></td></tr></table></figure><h2 id="4-使用Kylin-Sample测试"><a href="#4-使用Kylin-Sample测试" class="headerlink" title="4. 使用Kylin Sample测试"></a>4. 使用Kylin Sample测试</h2><p>Kylin本身自带了一个测试例子,创建流程如下:<br>执行sample.sh脚本,这个主要是创建kylin的project、model、cube以及相关的hive表等。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">[root@cdh-node-2 bin]# ./sample.sh</span><br><span class="line">Retrieving hadoop conf dir...</span><br><span class="line">Retrieving hadoop conf dir...</span><br><span class="line">KYLIN_HOME is set to /usr/local/kylin</span><br><span class="line">Loading sample data into HDFS tmp path: /tmp/kylin/sample_cube/d</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">Sample cube is created successfully in project 'learn_kylin'.</span><br><span class="line">Restart Kylin server or reload the metadata from web UI to see the change.</span><br></pre></td></tr></table></figure><p>进入Kylin Web界面system - reload metadata<br>然后构建示例的cube,如果构建成功,并且能成功执行查询命令,则表示整个配置全部完成。</p><p><img src="https://s1.ax1x.com/2018/09/14/iEhVEj.png" alt="构建成功"></p><p><img src="https://s1.ax1x.com/2018/09/14/iEhZUs.png" alt="查询成功"></p><hr><p>[1] Cloudera Configuring Authentication Doc: <a href="https://www.cloudera.com/documentation/enterprise/5-11-x/topics/sg_authentication.html" target="_blank" rel="noopener">https://www.cloudera.com/documentation/enterprise/5-11-x/topics/sg_authentication.html</a><br>[2] Kylin官网配置指南:<br><a href="http://kylin.apache.org/cn/docs/install/configuration.html" target="_blank" rel="noopener">http://kylin.apache.org/cn/docs/install/configuration.html</a><br>[3] Linux下的crontab定时执行任务命令详解:<br><a href="https://www.cnblogs.com/longjshz/p/5779215.html" target="_blank" rel="noopener">https://www.cnblogs.com/longjshz/p/5779215.html</a></p>]]></content>
<summary type="html">
<h2 id="1-概述"><a href="#1-概述" class="headerlink" title="1. 概述"></a>1. 概述</h2><p>本文首先会简单介绍Kylin的安装配置,然后介绍启用Kerberos的CDH集群中如何部署及使用Kylin。</p>
<p>Apache Kylin™是一个开源的分布式分析引擎,提供Hadoop/Spark之上的SQL查询接口及多维分析(OLAP)能力以支持超大规模数据,最初由eBay Inc. 开发并贡献至开源社区。它能在亚秒内查询巨大的Hive表。<br>
</summary>
<category term="BigData" scheme="http://mantoudev.com/categories/BigData/"/>
<category term="安全" scheme="http://mantoudev.com/categories/BigData/%E5%AE%89%E5%85%A8/"/>
<category term="Kerberos" scheme="http://mantoudev.com/tags/Kerberos/"/>
<category term="大数据安全" scheme="http://mantoudev.com/tags/%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%AE%89%E5%85%A8/"/>
<category term="Kylin" scheme="http://mantoudev.com/tags/Kylin/"/>
</entry>
<entry>
<title>[机器学习实战]决策树</title>
<link href="http://mantoudev.com/%5B%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E5%AE%9E%E6%88%98%5D%E5%86%B3%E7%AD%96%E6%A0%91/"/>
<id>http://mantoudev.com/[机器学习实战]决策树/</id>
<published>2018-04-21T03:27:00.000Z</published>
<updated>2018-11-27T14:34:03.565Z</updated>
<content type="html"><![CDATA[<h2 id="1-简介"><a href="#1-简介" class="headerlink" title="1. 简介"></a>1. 简介</h2><p> 决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概率分析的一种图解法。由于这种决策分支画成图形很像一棵树的枝干,故称决策树。在机器学习中,决策树是一个预测模型,他代表的是<code>对象属性</code>与<code>对象值</code>之间的一种映射关系。Entropy = 系统的凌乱程度,使用算法ID3, C4.5和C5.0生成树算法使用熵。这一度量是基于信息学理论中熵的概念。<br> <a id="more"></a></p><p>决策树是一种树形结构,其中每个内部节点表示一个属性上的测试,每个分支代表一个测试输出,每个叶节点代表一种类别。</p><p>决策树学习通常包括 3 个步骤:</p><ul><li>特征选择</li><li>决策树的生成</li><li>决策树的修剪</li></ul><h3 id="1-1-决策树场景"><a href="#1-1-决策树场景" class="headerlink" title="1.1 决策树场景"></a>1.1 决策树场景</h3><h5 id="场景一:二十个问题"><a href="#场景一:二十个问题" class="headerlink" title="场景一:二十个问题"></a>场景一:二十个问题</h5><p>有一个叫 “二十个问题” 的游戏,游戏规则很简单:参与游戏的一方在脑海中想某个事物,其他参与者向他提问,只允许提 20 个问题,问题的答案也只能用对或错回答。问问题的人通过推断分解,逐步缩小待猜测事物的范围,最后得到游戏的答案。</p><h5 id="场景二:邮件分类"><a href="#场景二:邮件分类" class="headerlink" title="场景二:邮件分类"></a>场景二:邮件分类</h5><p>一个邮件分类系统,大致工作流程如下:</p><p><img src="https://raw.love2.io/gaolinjie/MachineLearning/b4e6199f40af19a2ef53d694ccedab515aac7ffe/images/3.DecisionTree/%E5%86%B3%E7%AD%96%E6%A0%91-%E6%B5%81%E7%A8%8B%E5%9B%BE.jpg" alt="image"></p><p>首先检测发送邮件域名地址。如果地址为 myEmployer.com, 则将其放在分类 “无聊时需要阅读的邮件”中。<br>如果邮件不是来自这个域名,则检测邮件内容里是否包含单词 “曲棍球” , 如果包含则将邮件归类到 “需要及时处理的朋友邮件”,<br>如果不包含则将邮件归类到 “无需阅读的垃圾邮件” 。</p><h3 id="1-2-定义"><a href="#1-2-定义" class="headerlink" title="1.2 定义"></a>1.2 定义</h3><p>分类决策树模型是一种描述对实例进行分类的树形结构。决策树由<code>结点(node)</code>和<code>有向边(directed edge</code>)组成。</p><p>结点有两种类型:</p><ul><li>内部结点(internal node):表示一个特征或属性。</li><li>叶结点(leaf: node):表示一个类。</li></ul><p>用决策树分类,从根节点开始,对实例的某一特征进行测试,根据测试结果,将实例分配到其子结点;这时,每一个子结点对应着该特征的一个取值。如此递归地对实例进行测试并分配,直至达到叶结点。最后将实例分配到叶结点的类中。</p><h2 id="2-决策树原理"><a href="#2-决策树原理" class="headerlink" title="2. 决策树原理"></a>2. 决策树原理</h2><ul><li><strong>熵</strong>:<br>熵(entropy)指的是体系的混乱的程度,在不同的学科中也有引申出的更为具体的定义,是各领域十分重要的参量。</li><li><p><strong>信息熵(香农熵)</strong>:<br>是一种信息的度量方式,表示信息的混乱程度,也就是说:信息越有序,信息熵越低。例如:火柴有序放在火柴盒里,熵值很低,相反,熵值很高。</p></li><li><p><strong>信息增益</strong>:<br>在划分数据集前后信息发生的变化称为信息增益。</p></li></ul><h3 id="2-1-工作原理"><a href="#2-1-工作原理" class="headerlink" title="2.1 工作原理"></a>2.1 工作原理</h3><p>我们使用 createBranch() 方法构造一个决策树,如下所示:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">检测数据集中的所有数据的分类标签是否相同:</span><br><span class="line"> If so return 类标签</span><br><span class="line"> Else:</span><br><span class="line"> 寻找划分数据集的最好特征(划分之后信息熵最小,也就是信息增益最大的特征)</span><br><span class="line"> 划分数据集</span><br><span class="line"> 创建分支节点</span><br><span class="line"> for 每个划分的子集</span><br><span class="line"> 调用函数 createBranch (创建分支的函数)并增加返回结果到分支节点中</span><br><span class="line"> return 分支节点</span><br></pre></td></tr></table></figure><h3 id="2-2-决策树开发流程"><a href="#2-2-决策树开发流程" class="headerlink" title="2.2 决策树开发流程"></a>2.2 决策树开发流程</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">1. 收集数据:可以使用任何方法。</span><br><span class="line">2. 准备数据:树构造算法只适用于标称型数据,因此数值型数据必须离散化。</span><br><span class="line">3. 分析数据:可以使用任何方法,构造树完成之后,我们应该检查图形是否符合预期。</span><br><span class="line">4. 训练算法:构造树的数据结构。</span><br><span class="line">5. 测试算法:使用经验树计算错误率。(经验树没有搜索到较好的资料,有兴趣的同学可以来补充)</span><br><span class="line">6. 使用算法:此步骤可以适用于任何监督学习算法,而使用决策树可以更好地理解数据的内在含义。</span><br></pre></td></tr></table></figure><h3 id="2-3-决策树算法特点"><a href="#2-3-决策树算法特点" class="headerlink" title="2.3 决策树算法特点"></a>2.3 决策树算法特点</h3><ul><li><strong>优点</strong>:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据。</li><li><strong>缺点</strong>:可能会产生过度匹配问题。<br>适用数据类型:数值型和标称型。</li></ul><h2 id="3-实战案例"><a href="#3-实战案例" class="headerlink" title="3. 实战案例"></a>3. 实战案例</h2><h3 id="3-1-项目概述"><a href="#3-1-项目概述" class="headerlink" title="3.1 项目概述"></a>3.1 项目概述</h3><p>根据以下 2 个特征,将动物分成两类:鱼类和非鱼类。</p><p><strong>特征</strong>:</p><ul><li>不浮出水面是否可以生存</li><li>是否有脚蹼</li></ul><h3 id="3-2-开发流程"><a href="#3-2-开发流程" class="headerlink" title="3.2 开发流程"></a>3.2 开发流程</h3><h4 id="1-收集数据"><a href="#1-收集数据" class="headerlink" title="(1) 收集数据"></a>(1) 收集数据</h4><blockquote><p>可以使用任何方法</p></blockquote><p><img src="https://raw.love2.io/gaolinjie/MachineLearning/b4e6199f40af19a2ef53d694ccedab515aac7ffe/images/3.DecisionTree/DT_%E6%B5%B7%E6%B4%8B%E7%94%9F%E7%89%A9%E6%95%B0%E6%8D%AE.png" alt="image"></p><p>我们利用 createDataSet() 函数输入数据:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">def createDataSet():</span><br><span class="line"> dataSet = [[1, 1, 'yes'],</span><br><span class="line"> [1, 1, 'yes'],</span><br><span class="line"> [1, 0, 'no'],</span><br><span class="line"> [0, 1, 'no'],</span><br><span class="line"> [0, 1, 'no']]</span><br><span class="line"> labels = ['no surfacing', 'flippers']</span><br><span class="line"> return dataSet, labels</span><br></pre></td></tr></table></figure><h4 id="2-准备数据"><a href="#2-准备数据" class="headerlink" title="(2) 准备数据"></a>(2) 准备数据</h4><blockquote><p>树构造算法只适用于标称型数据,因此数值型数据必须离散化</p></blockquote><p>此处,由于我们输入的数据本身就是离散化数据,所以这一步就省略了。</p><h4 id="(3)-分析数据"><a href="#(3)-分析数据" class="headerlink" title="(3) 分析数据"></a>(3) 分析数据</h4><blockquote><p>可以使用任何方法,构造树完成之后,我们应该检查图形是否符合预期</p></blockquote><p><img src="https://raw.love2.io/gaolinjie/MachineLearning/b4e6199f40af19a2ef53d694ccedab515aac7ffe/images/3.DecisionTree/%E7%86%B5%E7%9A%84%E8%AE%A1%E7%AE%97%E5%85%AC%E5%BC%8F.jpg" alt="image"></p><h5 id="计算给定数据集的香农熵的函数"><a href="#计算给定数据集的香农熵的函数" class="headerlink" title="计算给定数据集的香农熵的函数"></a>计算给定数据集的香农熵的函数</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">def calcShannonEnt(dataSet):</span><br><span class="line"> # 求list的长度,表示计算参与训练的数据量</span><br><span class="line"> numEntries = len(dataSet)</span><br><span class="line"> # 计算分类标签label出现的次数</span><br><span class="line"> labelCounts = {}</span><br><span class="line"> # the the number of unique elements and their occurance</span><br><span class="line"> for featVec in dataSet:</span><br><span class="line"> # 将当前实例的标签存储,即每一行数据的最后一个数据代表的是标签</span><br><span class="line"> currentLabel = featVec[-1]</span><br><span class="line"> # 为所有可能的分类创建字典,如果当前的键值不存在,则扩展字典并将当前键值加入字典。每个键值都记录了当前类别出现的次数。</span><br><span class="line"> if currentLabel not in labelCounts.keys():</span><br><span class="line"> labelCounts[currentLabel] = 0</span><br><span class="line"> labelCounts[currentLabel] += 1</span><br><span class="line"></span><br><span class="line"> # 对于 label 标签的占比,求出 label 标签的香农熵</span><br><span class="line"> shannonEnt = 0.0</span><br><span class="line"> for key in labelCounts:</span><br><span class="line"> # 使用所有类标签的发生频率计算类别出现的概率。</span><br><span class="line"> prob = float(labelCounts[key])/numEntries</span><br><span class="line"> # 计算香农熵,以 2 为底求对数</span><br><span class="line"> shannonEnt -= prob * log(prob, 2)</span><br><span class="line"> return shannonEnt</span><br></pre></td></tr></table></figure><h5 id="按照给定特征划分数据集"><a href="#按照给定特征划分数据集" class="headerlink" title="按照给定特征划分数据集"></a>按照给定特征划分数据集</h5><p>将指定特征的特征值等于 value 的行剩下列作为子数据集。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">def splitDataSet(dataSet, index, value):</span><br><span class="line"> """splitDataSet(通过遍历dataSet数据集,求出index对应的colnum列的值为value的行)</span><br><span class="line"> 就是依据index列进行分类,如果index列的数据等于 value的时候,就要将 index 划分到我们创建的新的数据集中</span><br><span class="line"> Args:</span><br><span class="line"> dataSet 数据集 待划分的数据集</span><br><span class="line"> index 表示每一行的index列 划分数据集的特征</span><br><span class="line"> value 表示index列对应的value值 需要返回的特征的值。</span><br><span class="line"> Returns:</span><br><span class="line"> index列为value的数据集【该数据集需要排除index列】</span><br><span class="line"> """</span><br><span class="line"> retDataSet = []</span><br><span class="line"> for featVec in dataSet:</span><br><span class="line"> # index列为value的数据集【该数据集需要排除index列】</span><br><span class="line"> # 判断index列的值是否为value</span><br><span class="line"> if featVec[index] == value:</span><br><span class="line"> # chop out index used for splitting</span><br><span class="line"> # [:index]表示前index行,即若 index 为2,就是取 featVec 的前 index 行</span><br><span class="line"> reducedFeatVec = featVec[:index]</span><br><span class="line"> '''</span><br><span class="line"> 请百度查询一下: extend和append的区别</span><br><span class="line"> list.append(object) 向列表中添加一个对象object</span><br><span class="line"> list.extend(sequence) 把一个序列seq的内容添加到列表中</span><br><span class="line"> 1、使用append的时候,是将new_media看作一个对象,整体打包添加到music_media对象中。</span><br><span class="line"> 2、使用extend的时候,是将new_media看作一个序列,将这个序列和music_media序列合并,并放在其后面。</span><br><span class="line"> result = []</span><br><span class="line"> result.extend([1,2,3])</span><br><span class="line"> print result</span><br><span class="line"> result.append([4,5,6])</span><br><span class="line"> print result</span><br><span class="line"> result.extend([7,8,9])</span><br><span class="line"> print result</span><br><span class="line"> 结果:</span><br><span class="line"> [1, 2, 3]</span><br><span class="line"> [1, 2, 3, [4, 5, 6]]</span><br><span class="line"> [1, 2, 3, [4, 5, 6], 7, 8, 9]</span><br><span class="line"> '''</span><br><span class="line"> reducedFeatVec.extend(featVec[index+1:])</span><br><span class="line"> # [index+1:]表示从跳过 index 的 index+1行,取接下来的数据</span><br><span class="line"> # 收集结果值 index列为value的行【该行需要排除index列】</span><br><span class="line"> retDataSet.append(reducedFeatVec)</span><br><span class="line"> return retDataSet</span><br></pre></td></tr></table></figure><h5 id="选择最好的数据集划分方式"><a href="#选择最好的数据集划分方式" class="headerlink" title="选择最好的数据集划分方式"></a>选择最好的数据集划分方式</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line">def chooseBestFeatureToSplit(dataSet):</span><br><span class="line"> """chooseBestFeatureToSplit(选择最好的特征)</span><br><span class="line"></span><br><span class="line"> Args:</span><br><span class="line"> dataSet 数据集</span><br><span class="line"> Returns:</span><br><span class="line"> bestFeature 最优的特征列</span><br><span class="line"> """</span><br><span class="line"> # 求第一行有多少列的 Feature, 最后一列是label列嘛</span><br><span class="line"> numFeatures = len(dataSet[0]) - 1</span><br><span class="line"> # 数据集的原始信息熵</span><br><span class="line"> baseEntropy = calcShannonEnt(dataSet)</span><br><span class="line"> # 最优的信息增益值, 和最优的Featurn编号</span><br><span class="line"> bestInfoGain, bestFeature = 0.0, -1</span><br><span class="line"> # iterate over all the features</span><br><span class="line"> for i in range(numFeatures):</span><br><span class="line"> # create a list of all the examples of this feature</span><br><span class="line"> # 获取对应的feature下的所有数据</span><br><span class="line"> featList = [example[i] for example in dataSet]</span><br><span class="line"> # get a set of unique values</span><br><span class="line"> # 获取剔重后的集合,使用set对list数据进行去重</span><br><span class="line"> uniqueVals = set(featList)</span><br><span class="line"> # 创建一个临时的信息熵</span><br><span class="line"> newEntropy = 0.0</span><br><span class="line"> # 遍历某一列的value集合,计算该列的信息熵</span><br><span class="line"> # 遍历当前特征中的所有唯一属性值,对每个唯一属性值划分一次数据集,计算数据集的新熵值,并对所有唯一特征值得到的熵求和。</span><br><span class="line"> for value in uniqueVals:</span><br><span class="line"> subDataSet = splitDataSet(dataSet, i, value)</span><br><span class="line"> # 计算概率</span><br><span class="line"> prob = len(subDataSet)/float(len(dataSet))</span><br><span class="line"> # 计算信息熵</span><br><span class="line"> newEntropy += prob * calcShannonEnt(subDataSet)</span><br><span class="line"> # gain[信息增益]: 划分数据集前后的信息变化, 获取信息熵最大的值</span><br><span class="line"> # 信息增益是熵的减少或者是数据无序度的减少。最后,比较所有特征中的信息增益,返回最好特征划分的索引值。</span><br><span class="line"> infoGain = baseEntropy - newEntropy</span><br><span class="line"> print 'infoGain=', infoGain, 'bestFeature=', i, baseEntropy, newEntropy</span><br><span class="line"> if (infoGain > bestInfoGain):</span><br><span class="line"> bestInfoGain = infoGain</span><br><span class="line"> bestFeature = i</span><br><span class="line"> return bestFeature</span><br></pre></td></tr></table></figure><blockquote><p>Q:上面的 newEntropy 为什么是根据子集计算的呢?<br>A :因为我们在根据一个特征计算香农熵的时候,该特征的分类值是相同,这个特征这个分类的香农熵为 0;<br>这就是为什么计算新的香农熵的时候使用的是子集。</p></blockquote><h4 id="(4)训练算法"><a href="#(4)训练算法" class="headerlink" title="(4)训练算法"></a>(4)训练算法</h4><blockquote><p>构造树的数据结构</p></blockquote><p>创建树的函数代码如下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">def createTree(dataSet, labels):</span><br><span class="line"> classList = [example[-1] for example in dataSet]</span><br><span class="line"> # 如果数据集的最后一列的第一个值出现的次数=整个集合的数量,也就说只有一个类别,就只直接返回结果就行</span><br><span class="line"> # 第一个停止条件:所有的类标签完全相同,则直接返回该类标签。</span><br><span class="line"> # count() 函数是统计括号中的值在list中出现的次数</span><br><span class="line"> if classList.count(classList[0]) == len(classList):</span><br><span class="line"> return classList[0]</span><br><span class="line"> # 如果数据集只有1列,那么最初出现label次数最多的一类,作为结果</span><br><span class="line"> # 第二个停止条件:使用完了所有特征,仍然不能将数据集划分成仅包含唯一类别的分组。</span><br><span class="line"> if len(dataSet[0]) == 1:</span><br><span class="line"> return majorityCnt(classList)</span><br><span class="line"></span><br><span class="line"> # 选择最优的列,得到最优列对应的label含义</span><br><span class="line"> bestFeat = chooseBestFeatureToSplit(dataSet)</span><br><span class="line"> # 获取label的名称</span><br><span class="line"> bestFeatLabel = labels[bestFeat]</span><br><span class="line"> # 初始化myTree</span><br><span class="line"> myTree = {bestFeatLabel: {}}</span><br><span class="line"> # 注:labels列表是可变对象,在PYTHON函数中作为参数时传址引用,能够被全局修改</span><br><span class="line"> # 所以这行代码导致函数外的同名变量被删除了元素,造成例句无法执行,提示'no surfacing' is not in list</span><br><span class="line"> del(labels[bestFeat])</span><br><span class="line"> # 取出最优列,然后它的branch做分类</span><br><span class="line"> featValues = [example[bestFeat] for example in dataSet]</span><br><span class="line"> uniqueVals = set(featValues)</span><br><span class="line"> for value in uniqueVals:</span><br><span class="line"> # 求出剩余的标签label</span><br><span class="line"> subLabels = labels[:]</span><br><span class="line"> # 遍历当前选择特征包含的所有属性值,在每个数据集划分上递归调用函数createTree()</span><br><span class="line"> myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)</span><br><span class="line"> # print 'myTree', value, myTree</span><br><span class="line"> return myTree</span><br></pre></td></tr></table></figure><h4 id="(5)测试算法"><a href="#(5)测试算法" class="headerlink" title="(5)测试算法"></a>(5)测试算法</h4><blockquote><p>使用决策树执行分类<br>代码如下:</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">def classify(inputTree, featLabels, testVec):</span><br><span class="line"> """classify(给输入的节点,进行分类)</span><br><span class="line"></span><br><span class="line"> Args:</span><br><span class="line"> inputTree 决策树模型</span><br><span class="line"> featLabels Feature标签对应的名称</span><br><span class="line"> testVec 测试输入的数据</span><br><span class="line"> Returns:</span><br><span class="line"> classLabel 分类的结果值,需要映射label才能知道名称</span><br><span class="line"> """</span><br><span class="line"> # 获取tree的根节点对于的key值</span><br><span class="line"> firstStr = inputTree.keys()[0]</span><br><span class="line"> # 通过key得到根节点对应的value</span><br><span class="line"> secondDict = inputTree[firstStr]</span><br><span class="line"> # 判断根节点名称获取根节点在label中的先后顺序,这样就知道输入的testVec怎么开始对照树来做分类</span><br><span class="line"> featIndex = featLabels.index(firstStr)</span><br><span class="line"> # 测试数据,找到根节点对应的label位置,也就知道从输入的数据的第几位来开始分类</span><br><span class="line"> key = testVec[featIndex]</span><br><span class="line"> valueOfFeat = secondDict[key]</span><br><span class="line"> print '+++', firstStr, 'xxx', secondDict, '---', key, '>>>', valueOfFeat</span><br><span class="line"> # 判断分枝是否结束: 判断valueOfFeat是否是dict类型</span><br><span class="line"> if isinstance(valueOfFeat, dict):</span><br><span class="line"> classLabel = classify(valueOfFeat, featLabels, testVec)</span><br><span class="line"> else:</span><br><span class="line"> classLabel = valueOfFeat</span><br><span class="line"> return classLabel</span><br></pre></td></tr></table></figure><h4 id="(6)使用算法"><a href="#(6)使用算法" class="headerlink" title="(6)使用算法"></a>(6)使用算法</h4><blockquote><p>此步骤可以适用于任何监督学习算法,而使用决策树可以更好地理解数据的内在含义。</p></blockquote><p>构造决策树是很耗时的任务,即使很小的数据集也要花费几秒。如果用创建好的决策树解决分类问题就可以很快完成。</p><p>因此为了节省计算时间,最好能每次执行分类时调用已经构造好的决策树,为了解决这个问题,需要使用Python模块<code>pickle</code>序列化对象。序列化对象可以在磁盘上保存对象,并在需要的时候读取出来。任何对象都可以执行序列化,包括字典对象。</p><p>下面代码是使用pickle模块存储决策树:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">def storeTree(inputTree, filename):</span><br><span class="line"> impory pickle</span><br><span class="line"> fw = open(filename, 'w')</span><br><span class="line"> pickle.dump(inputTree, fw)</span><br><span class="line"> fw.close()</span><br><span class="line"></span><br><span class="line">def grabTree(filename):</span><br><span class="line"> import pickle</span><br><span class="line"> fr = open(filename)</span><br><span class="line"> return pickle.load(fr)</span><br></pre></td></tr></table></figure><p>通过上面的代码我们可以把分类器存储在硬盘上,而不用每次对数据分类时重新学习一遍,这也是决策树的优点之一。++K-近邻算法就无法持久化分类器++。</p><hr><p>[1] 决策树维基百科: <a href="https://zh.wikipedia.org/wiki/%E5%86%B3%E7%AD%96%E6%A0%91" target="_blank" rel="noopener">https://zh.wikipedia.org/wiki/%E5%86%B3%E7%AD%96%E6%A0%91</a><br>[2]《机器学习实战》 – Peter Harrington<br>[3]《机器学习》 – 周志华</p>]]></content>
<summary type="html">
<h2 id="1-简介"><a href="#1-简介" class="headerlink" title="1. 简介"></a>1. 简介</h2><p> 决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概率分析的一种图解法。由于这种决策分支画成图形很像一棵树的枝干,故称决策树。在机器学习中,决策树是一个预测模型,他代表的是<code>对象属性</code>与<code>对象值</code>之间的一种映射关系。Entropy = 系统的凌乱程度,使用算法ID3, C4.5和C5.0生成树算法使用熵。这一度量是基于信息学理论中熵的概念。<br>
</summary>
<category term="机器学习" scheme="http://mantoudev.com/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="机器学习" scheme="http://mantoudev.com/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="决策树" scheme="http://mantoudev.com/tags/%E5%86%B3%E7%AD%96%E6%A0%91/"/>
</entry>
<entry>
<title>[机器学习Lesson 4]多元线性回归</title>
<link href="http://mantoudev.com/%5B%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0Lesson%204%5D%E5%A4%9A%E5%85%83%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/"/>
<id>http://mantoudev.com/[机器学习Lesson 4]多元线性回归/</id>
<published>2018-04-18T01:01:00.000Z</published>
<updated>2018-11-27T14:33:53.789Z</updated>
<content type="html"><![CDATA[<h2 id="1-多元线性回归定义"><a href="#1-多元线性回归定义" class="headerlink" title="1. 多元线性回归定义"></a>1. 多元线性回归定义</h2><p>在回归分析中,如果有两个或两个以上的自变量,就称为多元回归。事实上,一种现象常常是与多个因素相联系的,由多个自变量的最优组合共同来预测或估计因变量,比只用一个自变量进行预测或估计更有效,更符合实际。因此多元线性回归比一元线性回归的实用意义更大。<br>我们现在介绍方程的符号,我们可以有任意数量的输入变量。<br><a id="more"></a></p><p><img src="https://s1.ax1x.com/2018/04/16/CmlqbR.png" alt="image"></p><p>这些多个特征的假设函数的多变量形式如下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hθ(x)=θ0+θ1x1+θ2x2+θ3x3+⋯+θnxn</span><br></pre></td></tr></table></figure><p>为了开发这个功能,我们可以想一想,θ0作为房子的基本价格,θ1每平方米的价格,θ2每层楼的价格,等X1将在房子的平方米数,x2楼层数,等等。</p><p>利用矩阵乘法的定义,我们的多变量假设函数可以简洁地表示为:</p><p><img src="https://s1.ax1x.com/2018/04/16/CmlxPK.png" alt="image"></p><p>这是对一个训练例子的假设函数的矢量化。</p><blockquote><p>备注:为了方便的原因,在这个过程中我们假设X(i)0 = 1(i∈1,…,m)。这允许我们做矩阵运算与θ和X使两向量的θ和X(i)互相匹配元素(即有相同数目的元素:N + 1)]。</p></blockquote><h2 id="2-梯度下降"><a href="#2-梯度下降" class="headerlink" title="2. 梯度下降"></a>2. 梯度下降</h2><p>下面我们使用梯度下降法来解决多特征的线性回归问题。</p><p><img src="https://s1.ax1x.com/2018/04/17/Cmc3jJ.png" alt="image"></p><ul><li><strong>Hypothesis:</strong> 假设假设现有多元线性回归并约定x0=1。</li><li><strong>Parameters:</strong> 该模型的参数是从θ0 到θn。不要认为这是 n+1 个单独的参数。你可以把这 n+1 个 θ 参数想象成一个 n+1 维的向量 θ。所以,现在就可以把这个模型的参数 想象成其本身就是一个 n+1 维的向量。</li><li><p><strong>Cost function:</strong> 我们的代价函数是从 θ0 到 θn 的函数 J,并给出了误差项平方的和。但同样地,不要把函数 J想成是一个关于 n+1 个自变量的函数,而是看成带有一个 n+1 维向量的函数。</p></li><li><p><strong>Gradient descent(梯度下降)</strong>: 我们将会不停地用 θj 减去 α 倍的导数项,来替代 θj 同样的方法。我们写出函数J(θ) 因此 θj 被更新成 θj 减去学习率 α 与对应导数的乘积 就是代价函数的对参数 θj 的偏导数。</p></li></ul><h3 id="2-1-当特征-n-1-时"><a href="#2-1-当特征-n-1-时" class="headerlink" title="2.1 当特征 n=1 时"></a>2.1 当特征 n=1 时</h3><p><img src="https://s1.ax1x.com/2018/04/17/Cmcsud.jpg" alt="image"></p><p> 我们有两条针对参数 θ0 和 θ1 不同的更新规则。①处是代价函数里部分求导的结果 ,是代价函数相对于 θ0 的偏导数。 同样,对参数 θ1 我们有另一个更新规则 仅有的一点区别是:当我们之前只有一个特征,我们称该特征为x(i)。 但现在我们在新符号里,我们会标记它为 x 上标 (i) 下标1来表示我们的特征。以上就是当我们仅有一个特征时候的算法。</p><h3 id="2-2-当有一个以上特征时"><a href="#2-2-当有一个以上特征时" class="headerlink" title="2.2 当有一个以上特征时"></a>2.2 当有一个以上特征时</h3><p> 现有数目远大于1的很多特征,梯度下降更新规则变成了这样:</p><p><img src="https://s1.ax1x.com/2018/04/18/CntrNj.png" alt="image"></p><p>有些同学可能知道微积分,代价函数 J 对参数 θj 求偏导数 (蓝线圈出部分),你将会得到多元线性回归的梯度下降算法。</p><p>新旧两种算法实际上是两个是类似的算法。为什么它们都是梯度下降算法?考虑这样一个情况:有两个或以上个数的特征,同时我们对θ1、θ2、θ3的三条更新规则,当然可能还有其它参数。如果你观察θ0的更新规则,你会发现这跟之前 n=1的情况相同。它们之所以是等价的这是因为在我们的标记约定里有 x(i)0=1,),也就红线圈起部分的两项是等价的。</p><p>同样地,如果你观察θ1的更新规则你会发现这里的这一项是和之前对参数θ1的更新项是等价的。在这里我们只是用了新的符号x(i)1来表示我们的第一个特征。现在我们有个更多的特征,那么就可以用与之前相同的更新规则,我们可以用同样的规则来处理 θ2 等其它参数。</p><h2 id="3-Feature-Scaling(特征缩放)"><a href="#3-Feature-Scaling(特征缩放)" class="headerlink" title="3. Feature Scaling(特征缩放)"></a>3. Feature Scaling(特征缩放)</h2><p>如果你有一个机器学习问题,这个问题有多个特征,如果你能确保这些特征都处在一个相近的范围,确保不同特征的取值在相近的范围内,这样梯度下降法就能更快地收敛。</p><h2 id="3-1-介绍"><a href="#3-1-介绍" class="headerlink" title="3.1 介绍"></a>3.1 介绍</h2><p>假如你有一个具有两个特征的问题:其中,x1是房屋面积大小,它的取值在0到2000之间。x2是卧室的数量,可能这个值取值范围在1到5之间。 如果你画出代价函数J(θ)的轮廓图,那么这个轮廓看起来应该是像下图这样的:</p><p><img src="https://s1.ax1x.com/2018/04/18/Cnt2vV.png" alt="image"></p><p>J(θ) 是一个关于参数 θ0 θ1 和 θ2 的函数(此处忽略 θ0 所以暂时不考虑θ0)。并假想一个函数的变量只有 θ1 和 θ2。 但如果x1的取值范围远远大于x2的取值范围的话,那么最终画出来的代价函数J(θ)的轮廓图就会呈现出这样一种非常偏斜,并且椭圆的形状 2000 和 5的比例 会让这个椭圆更加瘦长。所以,这是一个又瘦又高的 椭圆形轮廓图 就是这些非常高大细长的椭圆形构成了代价函数 J(θ) 。</p><p>而如果你用这个代价函数来运行梯度下降的话,你要得到梯度值,最终可能需要花很长一段时间并且可能会来回波动,然后会经过很长时间,最终才收敛到全局最小值。</p><p>可以想像,如果这些轮廓再被放大一些的话,如果你画的再夸张一些,把它画的更细更长,那么可能情况会更糟糕 。梯度下降的过程可能更加缓慢,需要花更长的时间,反复来回振荡,最终才找到一条正确通往全局最小值的路。</p><p>在这样的情况下一种有效的方法是进行<code>特征缩放(feature scaling)</code> 。</p><p><img src="https://s1.ax1x.com/2018/04/18/CnN5sf.md.png" alt="image"></p><p>具体来说,把特征x定义为房子的面积大小,除以2000; 并且把x2定义为卧室的数量除以5。那么这样的话 表示代价函数 J(θ) 的轮廓图的形状就会变得偏移没那么严重,可能看起来更圆一些了。<br>如果你用这样的代价函数来执行梯度下降的话,可以从数学上来证明,梯度下降算法就会找到一条更捷径的路径通向全局最小,而不是像刚才那样沿着一条让人摸不着头脑的路径,一条复杂得多的轨迹,来找到全局最小值。</p><p>因此,通过特征缩放,通过”消耗掉”这些值的范围,在这个例子中,我们最终得到的两个特征 x1 和 x2 都在0和1之间,这样你得到的梯度下降算法就会更快地收敛。</p><h3 id="3-2-特征范围"><a href="#3-2-特征范围" class="headerlink" title="3.2 特征范围"></a>3.2 特征范围</h3><p> 我们执行特征缩放时,通常的目的是将特征的取值约束到-1到+1的范围内:</p><p> <img src="https://s1.ax1x.com/2018/04/18/CnthbF.png" alt="image"></p><p>你的特征x0是总是等于1,因此这已经是在这个范围内。<br>但对其他的特征 你可能需要通过除以不同的数 来让它们处于同一范围内。-1 和 +1这两个数字并不是太重要,所以 如果你有一个特征x1 它的取值在0和3之间,是没问题的。如果你有另外一个特征取值在-2 到 +0.5之间这也没什么关系,这也非常接近 -1 到 +1的范围,这些都可以。</p><p>但如果你有另一个特征,比如叫 x3 假如它的范围在 -100到+100之间,那么这个范围跟-1到+1就有很大不同了。所以这可能是一个不那么好的特征。类似地,如果你的特征在一个非常非常小的范围内,比如另外一个特征 x4 它的范围在 0.0001和+0.0001之间,那么这同样是一个 比-1到+1小得多的范围。因此同样会认为这个特征也不太好。</p><p>所以,可能你认可的范围也许可以大于或者小于-1到+1,但是也别太大,只要大得不多就可以接受。比如 +100 或者也别太小,比如这里的0.001。不同的人有不同的经验。但是我一般是这么考虑的,如果一个特征是在 -3 到 +3 的范围内,那么你应该认为这个范围是可以接受的。 但如果这个范围大于了-3到+3的范围,我可能就要开始注意了。如果它的取值 在-1/3 到+1/3的话,我觉得 还不错,可以接受。或者是0到1/3或-1/3到0,这些典型的范围,我都认为是可以接受的。但如果特征的范围 取得很小的话,比如像这里的0.0001你就要开始考虑进行特征缩放了。</p><p>因此,总的来说不用过于担心你的特征是否在完全 相同的范围或区间内,但是只要他们都只要它们足够接近的话,梯度下降法就会正常地工作。</p><h3 id="3-3-Mean-Normalization-均值归一化"><a href="#3-3-Mean-Normalization-均值归一化" class="headerlink" title="3.3 Mean Normalization(均值归一化)"></a>3.3 Mean Normalization(均值归一化)</h3><p>除了在特征缩放中将特征除以最大值以外,有时候我们也会进行一个称为均值归一化的工作(mean normalization) 。</p><p><img src="https://s1.ax1x.com/2018/04/18/CnNZVg.png" alt="image"></p><p>如果你有一个特征 xi 你就用xi-μi来替换,通过这样做 让你的特征值具有为0的平均值。我们不需要把这一步应用到x0中,因为x0总是等于1的,所以它不可能有为0的的平均值。但是对其他的特征来说,比如房子的大小,取值介于0到2000,并且假设房子面积的平均值是等于1000的。那么你可以用这个公式将x1的值变为,x1减去平均值μ1再除以2000。类似地,如果你的房子有五间卧室 ,并且平均一套房子有两间卧室,那么可以使用这个公式来归一化你的第二个特征x2。</p><p>在这两种情况下,你可以算出新的特征x1和x2这样它们的范围可以在-0.5和+0.5之间,当然这肯定不对。x2的值实际上肯定会大于0.5,但很接近。更一般的规律是 你可以用这样的公式:<code>(x1 - μ1)/S1</code>来替换原来的特征x1。其中定义μ1的意思是: 在训练集中:</p><ul><li>x1:平均值</li><li>S1:特征值的范围(最大值减去最小值 最大值减去最小值,或者学过标准差的同学可以记住 也可以把S1设为变量的标准差,但其实用最大值减最小值就可以了)</li></ul><p>类似地,对于第二个 特征 x2 你也可以用同样的这个<br>特征减去平均值,再除以范围来替换原特征。范围的意思依然是最大值减最小值。这类公式将你的特征 变成这样的范围,也许不是完全这样,但大概是这样的范围。</p><p>有些同学可能比较仔细,如果我们用最大值减最小值来表示范围的话。这里的5有可能应该是4 如果最大值为5,那么减去最小值1,这个范围值就是4 。但不管咋说,这些取值都是非常近似的,只要将特征转换为相近似的范围就都是可以的。</p><p>特征缩放其实并不需要太精确,只是为了让梯度下降 能够运行得更快一点而已。</p><h2 id="4-Learning-Rate-学习效率"><a href="#4-Learning-Rate-学习效率" class="headerlink" title="4. Learning Rate(学习效率)"></a>4. Learning Rate(学习效率)</h2><p>这一章节我们来介绍如何选择学习率α 以及怎样确定 梯度下降正常工作。</p><ul><li><p><strong>Debugging gradient descent(调试渐变下降)</strong>:用X轴上的迭代次数绘制一个图。现在小区的成本函数,J(θ)在梯度下降迭代次数。如果J(θ)不断增加,那么你可能需要减少α。</p></li><li><p><strong>Automatic convergence test(自动收敛测试)</strong> :如果该声明收敛(θ)小于E在一次迭代中减少,其中E是一些小的值,如10−3。然而,在实际应用中很难选择这个阈值。</p></li></ul><p><img src="https://s1.ax1x.com/2018/04/18/CnNBM6.png" alt="image"></p><p>如果学习率α足够小,那么J(θ)会在每个迭代中减少。</p><p><img src="https://s1.ax1x.com/2018/04/18/CnNdR1.png" alt="image"></p><h5 id="总结:"><a href="#总结:" class="headerlink" title="总结:"></a>总结:</h5><ul><li>如果α太小:收敛速度慢。</li><li>如果α太大:可能不会在每次迭代中减少,因此可能不会收敛。</li></ul><hr><p>本文资料部分来源于吴恩达 (Andrew Ng) 博士的斯坦福大学机器学习公开课视频教程。 </p><p>[1] 网易云课堂机器学习课程:<br><a href="http://open.163.com/special/opencourse/machinelearning.html" target="_blank" rel="noopener">http://open.163.com/special/opencourse/machinelearning.html</a><br>[2] coursera课程:<br><a href="https://www.coursera.org/learn/machine-learning/" target="_blank" rel="noopener">https://www.coursera.org/learn/machine-learning/</a></p>]]></content>
<summary type="html">
<h2 id="1-多元线性回归定义"><a href="#1-多元线性回归定义" class="headerlink" title="1. 多元线性回归定义"></a>1. 多元线性回归定义</h2><p>在回归分析中,如果有两个或两个以上的自变量,就称为多元回归。事实上,一种现象常常是与多个因素相联系的,由多个自变量的最优组合共同来预测或估计因变量,比只用一个自变量进行预测或估计更有效,更符合实际。因此多元线性回归比一元线性回归的实用意义更大。<br>我们现在介绍方程的符号,我们可以有任意数量的输入变量。<br>
</summary>
<category term="机器学习" scheme="http://mantoudev.com/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="机器学习" scheme="http://mantoudev.com/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="线性回归" scheme="http://mantoudev.com/tags/%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/"/>
</entry>
<entry>
<title>[机器学习实战]K-近邻算法</title>
<link href="http://mantoudev.com/%5B%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E5%AE%9E%E6%88%98%5DK-%E8%BF%91%E9%82%BB%E7%AE%97%E6%B3%95/"/>
<id>http://mantoudev.com/[机器学习实战]K-近邻算法/</id>
<published>2018-04-10T16:20:00.000Z</published>
<updated>2018-11-27T14:33:59.117Z</updated>
<content type="html"><![CDATA[<h2 id="1-K-近邻算法概述-k-Nearest-Neighbor,KNN"><a href="#1-K-近邻算法概述-k-Nearest-Neighbor,KNN" class="headerlink" title="1. K-近邻算法概述(k-Nearest Neighbor,KNN)"></a>1. K-近邻算法概述(k-Nearest Neighbor,KNN)</h2><p>K-近邻算法采用测量不同的特征值之间的距离方法进行分类。该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。<br><a id="more"></a></p><ul><li><strong>优点</strong>:精度高、对异常数据不敏感、无数据输入假定。</li><li><strong>缺点</strong>:计算复杂度高、空间复杂度高。</li><li><strong>适用数据范围</strong>:数值型和标称型。</li></ul><p><strong>KNN工作原理</strong>是:存在一个样本数据集合(训练样本集),并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。输入没有标签的新数据后,将新数据每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似的数据(最近邻)的分类标签。</p><p>一般来说我们只选择样本数据集中前k个最相似的数据。通常k是不大于20的整数。最后选择k个最相似数据中出现次数最多的分类,作为新数据的分类。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">KNN的一般流程:</span><br><span class="line"></span><br><span class="line">1.收集数据:可使用任何方法。</span><br><span class="line">2.准备数据:距离计算所需要的数值,最好是结构化的数据格式。</span><br><span class="line">3.分析数据:可使用任何方法。</span><br><span class="line">4.训练算法:此步骤不适用与K-近邻算法</span><br><span class="line">5.测试算法:计算错误率。</span><br><span class="line">6.使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。</span><br></pre></td></tr></table></figure><h2 id="2-准备数据集"><a href="#2-准备数据集" class="headerlink" title="2. 准备数据集"></a>2. 准备数据集</h2><p>在构造完整的k-近邻算法之前,我们还需要编写一些基本的通用函数,新建KNN.py文件,新增以下代码:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">#!/usr/bin/python</span><br><span class="line"># -*- coding: UTF-8 -*-</span><br><span class="line">from numpy import *</span><br><span class="line"></span><br><span class="line">"""</span><br><span class="line">函数说明:创建数据集</span><br><span class="line"></span><br><span class="line">Parameters:</span><br><span class="line"> 无</span><br><span class="line">Returns:</span><br><span class="line"> group - 数据集</span><br><span class="line"> labels - 分类标签</span><br><span class="line">"""</span><br><span class="line">def createDataSet():</span><br><span class="line"> #四组二维特征</span><br><span class="line"> group = array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])</span><br><span class="line"> #四组特征的标签</span><br><span class="line"> labels = ['A','B','C','D']</span><br><span class="line"> return group, labels</span><br><span class="line"></span><br><span class="line">if __name__ == '__main__':</span><br><span class="line"> #创建数据集</span><br><span class="line"> group, labels = createDataSet()</span><br><span class="line"> #打印数据集</span><br><span class="line"> print(group)</span><br><span class="line"> print(labels)</span><br></pre></td></tr></table></figure><h2 id="3-k-近邻算法实现"><a href="#3-k-近邻算法实现" class="headerlink" title="3. k-近邻算法实现"></a>3. k-近邻算法实现</h2><p>对未知类别属性的数据集中的每个点一次执行以下操作:</p><ol><li>计算已知类别数据集中的点与当前点之间的距离;</li><li>按照距离增序排序;</li><li>选取与当前点距离最近的k个点;</li><li>决定这k个点所属类别的出现频率;</li><li>返回前k个点出现频率最高的类别作为当前点的预测分类。</li></ol><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"># -*- coding: UTF-8 -*-</span><br><span class="line">from numpy import *</span><br><span class="line">import operator</span><br><span class="line"></span><br><span class="line">"""</span><br><span class="line">函数说明:kNN算法,分类器</span><br><span class="line"></span><br><span class="line">Parameters:</span><br><span class="line"> inX - 用于分类的数据(测试集)</span><br><span class="line"> dataSet - 用于训练的数据(训练集)</span><br><span class="line"> labes - 分类标签</span><br><span class="line"> k - kNN算法参数,选择距离最小的k个点</span><br><span class="line">Returns:</span><br><span class="line"> sortedClassCount[0][0] - 分类结果</span><br><span class="line">"""</span><br><span class="line">def classify0(inX, dataSet, labels, k):</span><br><span class="line"> #numpy函数shape[0]返回dataSet的行数</span><br><span class="line"> dataSetSize = dataSet.shape[0]</span><br><span class="line"> #在列向量方向上重复inX共1次(横向),行向量方向上重复inX共dataSetSize次(纵向)</span><br><span class="line"> diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet</span><br><span class="line"> #二维特征相减后平方</span><br><span class="line"> sqDiffMat = diffMat**2</span><br><span class="line"> #sum()所有元素相加,sum(0)列相加,sum(1)行相加</span><br><span class="line"> sqDistances = sqDiffMat.sum(axis=1)</span><br><span class="line"> #开方,计算出距离</span><br><span class="line"> distances = sqDistances**0.5</span><br><span class="line"> #返回distances中元素从小到大排序后的索引值</span><br><span class="line"> sortedDistIndices = distances.argsort()</span><br><span class="line"> #定一个记录类别次数的字典</span><br><span class="line"> classCount = {}</span><br><span class="line"> for i in range(k):</span><br><span class="line"> #取出前k个元素的类别</span><br><span class="line"> voteIlabel = labels[sortedDistIndices[i]]</span><br><span class="line"> #dict.get(key,default=None),字典的get()方法,返回指定键的值,如果值不在字典中返回默认值。</span><br><span class="line"> #计算类别次数</span><br><span class="line"> classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1</span><br><span class="line"> #python3中用items()替换python2中的iteritems()</span><br><span class="line"> #key=operator.itemgetter(1)根据字典的值进行排序</span><br><span class="line"> #key=operator.itemgetter(0)根据字典的键进行排序</span><br><span class="line"> #reverse降序排序字典</span><br><span class="line"> sortedClassCount = sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse=True)</span><br><span class="line"> #返回次数最多的类别,即所要分类的类别</span><br><span class="line"> return sortedClassCount[0][0]</span><br></pre></td></tr></table></figure><p>计算距离时直接使用了欧式距离公式,计算两个向量点之间的距离:</p><p><img src="https://gss2.bdstatic.com/9fo3dSag_xI4khGkpoWK1HF6hhy/baike/s%3D191/sign=7bb3375e3c4e251fe6f7e0f19687c9c2/e7cd7b899e510fb335a3e2f3d533c895d1430c1f.jpg" alt="image"></p><p>计算完所有点之间的距离后,可以对数据按照从小到大的次序排序。然后,确定前k个距离最小元素所在的主要分类,输入k总是正整数;最后,将classCount字典分解为元组列表,然后按照第二个元素的次序对元组进行排序,最后返回发生频率最高的元素标签。</p><p>预测数据所在分类:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">>>> kNN.classify([0, 0], group, labels, 3)</span><br></pre></td></tr></table></figure><p>输出结果应该是B。</p><h2 id="4-测试分类器"><a href="#4-测试分类器" class="headerlink" title="4. 测试分类器"></a>4. 测试分类器</h2><p>为了测试分类器的效果,我们可以使用已知答案的数据,当然答案不能告诉分类器,检验分类器给出的结果是否符合预期结果。通过大量的测试数据,我们可以得到分类器的错误率——分类器给出错误结果的次数除以测试执行的总数。错误率是常用的评估方法,主要用于评估分类器在某个数据集上的执行效果。完美分类器的错误率为0,最差分类器的错误率是1.0,在这种情况下,分类器根本就无法找到一个正确答案。然而错误率几乎不会达到1.0,因为即使是随机猜测,也会有一定概率猜对的。因此,错误率一般存在一个上限,且具体的值会与各类型之间的比例关系直接相关。</p><hr><p>[1]KNN维基百科:<br><a href="https://zh.wikipedia.org/wiki/%E6%9C%80%E8%BF%91%E9%84%B0%E5%B1%85%E6%B3%95" target="_blank" rel="noopener">https://zh.wikipedia.org/wiki/%E6%9C%80%E8%BF%91%E9%84%B0%E5%B1%85%E6%B3%95</a></p><p>我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:<a href="https://cloud.tencent.com/developer/support-plan?invite_code=b5vh0mme3g9n" target="_blank" rel="noopener">https://cloud.tencent.com/developer/support-plan?invite_code=b5vh0mme3g9n</a></p>]]></content>
<summary type="html">
<h2 id="1-K-近邻算法概述-k-Nearest-Neighbor,KNN"><a href="#1-K-近邻算法概述-k-Nearest-Neighbor,KNN" class="headerlink" title="1. K-近邻算法概述(k-Nearest Neighbor,KNN)"></a>1. K-近邻算法概述(k-Nearest Neighbor,KNN)</h2><p>K-近邻算法采用测量不同的特征值之间的距离方法进行分类。该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。<br>
</summary>
<category term="机器学习" scheme="http://mantoudev.com/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="机器学习" scheme="http://mantoudev.com/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="K-近邻" scheme="http://mantoudev.com/tags/K-%E8%BF%91%E9%82%BB/"/>
</entry>
<entry>
<title>[机器学习Lesson 3]梯度下降算法</title>
<link href="http://mantoudev.com/%5B%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0Lesson%203%5D%E6%A2%AF%E5%BA%A6%E4%B8%8B%E9%99%8D%E7%AE%97%E6%B3%95/"/>
<id>http://mantoudev.com/[机器学习Lesson 3]梯度下降算法/</id>
<published>2018-03-26T15:33:00.000Z</published>
<updated>2018-11-28T11:08:53.951Z</updated>
<content type="html"><![CDATA[<h2 id="1-Gradient-Descent(梯度下降)"><a href="#1-Gradient-Descent(梯度下降)" class="headerlink" title="1. Gradient Descent(梯度下降)"></a>1. Gradient Descent(梯度下降)</h2><p>梯度下降算法是很常用的算法,可以将代价函数J最小化。它不仅被用在线性回归上,也被广泛应用于机器学习领域中的众多领域。</p><a id="more"></a><h3 id="1-1-线性回归问题应用"><a href="#1-1-线性回归问题应用" class="headerlink" title="1.1 线性回归问题应用"></a>1.1 线性回归问题应用</h3><p>我们有一个函数<code>J(θ0,θ1)</code>,要使其最小化<code>minJ(θ0,θ01)</code>:</p><p><img src="https://s1.ax2x.com/2018/04/08/IPxlB.png" alt="<图1>"></p><p><strong>Outline</strong></p><ul><li>对θ0,θ1开始进行一些猜测<br>通常将初θ0,θ1初始化为0</li><li>在梯度算法中,要做的就是不停的一点点改变θ0和θ1试图通过这种改变使得J(θ0,θ1)变小,直到找到J的最小值或者局部最小值。</li></ul><h3 id="1-2-梯度算法工作原理"><a href="#1-2-梯度算法工作原理" class="headerlink" title="1.2 梯度算法工作原理"></a>1.2 梯度算法工作原理</h3><p><img src="https://s1.ax2x.com/2018/04/08/Ia9VQ.png" alt="<图2>"></p><p>现在我们把这个图像想象为一座山,想像类似这样的景色 :公园中有两座山,想象一下你正站立在山的这一点上 站立在你想象的公园这座红色山上。在梯度下降算法中,我们要做的就是旋转360度,看看我们的周围,并问自己,我要在某个方向上,用小碎步尽快下山。如果我想要下山。如果我想尽快走下山,这些小碎步需要朝什么方向? 如果我们站在山坡上的这一点,你看一下周围,你会发现最佳的下山方向,大约是那个方向。 </p><p>现在你在山上的新起点上 你再看看周围 然后再一次想想 我应该从什么方向迈着小碎步下山? 然后你按照自己的判断又迈出一步 往那个方向走了一步 然后重复上面的步骤。从这个新的点,你环顾四周并决定从什么方向将会最快下山。然后又迈进了一小步,并依此类推,直到你接近这里,直到局部最低点的位置。</p><p><img src="https://s1.ax2x.com/2018/04/08/Ia32E.md.png" alt="image"></p><p>现在想象一下,我们在刚才的右边一些的位置,对梯度下降进行初始化。想象我们在右边高一些的这个点。开始使用梯度下降。如果你重复上述步骤,停留在该点,并环顾四周,往下降最快的方向迈出一小步,然后环顾四周又迈出一步,然后如此往复。如果你从右边不远处开始梯度下降算法将会带你来到这个右边的第二个局部最优处。 如果从刚才的第一个点出发,你会得到这个局部最优解 但如果你的起始点偏移了一些,起始点的位置略有不同 你会得到一个非常不同的局部最优解。这就是梯度下降算法的一个特点。</p><h3 id="1-3-梯度下降算法定义。"><a href="#1-3-梯度下降算法定义。" class="headerlink" title="1.3 梯度下降算法定义。"></a>1.3 梯度下降算法定义。</h3><p><img src="https://s1.ax2x.com/2018/04/08/IaHFz.png" alt="<图4>"></p><ul><li><code>:=</code>:赋值符号(Assignment).</li><li><code>α</code>:这里的α是一个数字,被称为学习速率(learning rate)。在梯度下降算法中,它控制了我们下山时会迈出多大的步子。</li><li><p>微分项。</p><p>在梯度下降中,我们要更新θ0和θ1。当 j=0 和 j=1 时 会产生更新。所以你将更新J、θ0还有θ1。实现梯度下降算法的微妙之处是,在这个表达式中,如果你要更新这个等式,你需要同时更新 θ0和θ1。</p></li></ul><p><img src="https://s1.ax2x.com/2018/04/08/IaTsS.png" alt="<图5>"></p><p>θ0和θ1需要同步更新,右侧是非同步更新,错误。</p><h3 id="1-4-梯度下降和代价函数"><a href="#1-4-梯度下降和代价函数" class="headerlink" title="1.4 梯度下降和代价函数"></a>1.4 梯度下降和代价函数</h3><p> 梯度下降是很常用的算法,它不仅被用在线性回归上 和线性回归模型还有平方误差代价函数。<br> 当具体应用到线性回归的情况下,可以推导出一种新形式的梯度下降法方程:</p><p> <img src="https://s1.ax2x.com/2018/04/09/INpC2.png" alt="image"></p><ul><li>m:训练集的大小</li><li>θ0与θ1同步改变</li><li>xi和yi:给定的训练集的值(数据)。</li></ul><p>我们已经分离出两例θj:θ0和θ1为独立的方程;在θ1中,在推导最后乘以Xi。以下是推导∂/∂θjJ(θ)的一个例子:</p><p><img src="http://wx2.sinaimg.cn/mw690/0060lm7Tly1fq6tgs5x0bj309s05a3yt.jpg" alt="image"></p><p>这一切的关键是,如果我们从猜测我们的假设开始,然后反复应用这些梯度下降方程,我们的假设将变得越来越精确。</p><p>因此,这只是原始成本函数J的梯度下降。这个方法是在每个步骤的每个训练集中的每一个例子,被称为批量梯度下降。注意,虽然梯度下降一般容易受到局部极小值的影响,但我们在线性回归中所提出的优化问题只有一个全局,没有其他局部最优解,因此梯度下降总是收敛(假定学习率α不是太大)到全局最小值。实际上,j是凸二次函数。这里是一个梯度下降的例子,它是为了最小化二次函数而运行的。</p><p><img src="https://s1.ax1x.com/2018/04/09/CFFmXn.png" alt="image"></p><p>上面所示的椭圆是二次函数的轮廓图。也表明是通过梯度下降的轨迹,它被初始化为(48,30)。X在图(连接的直线)的标志,θ梯度穿过它收敛到最小的连续值。</p><hr><p>本文资料部分来源于吴恩达 (Andrew Ng) 博士的斯坦福大学机器学习公开课视频教程。 </p><p>[1]网易云课堂机器学习课程:<br><a href="http://open.163.com/special/opencourse/machinelearning.html" target="_blank" rel="noopener">http://open.163.com/special/opencourse/machinelearning.html</a><br>[2]coursera课程:<br><a href="https://www.coursera.org/learn/machine-learning/" target="_blank" rel="noopener">https://www.coursera.org/learn/machine-learning/</a></p>]]></content>
<summary type="html">
<h2 id="1-Gradient-Descent(梯度下降)"><a href="#1-Gradient-Descent(梯度下降)" class="headerlink" title="1. Gradient Descent(梯度下降)"></a>1. Gradient Descent(梯度下降)</h2><p>梯度下降算法是很常用的算法,可以将代价函数J最小化。它不仅被用在线性回归上,也被广泛应用于机器学习领域中的众多领域。</p>
</summary>
<category term="机器学习" scheme="http://mantoudev.com/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="机器学习" scheme="http://mantoudev.com/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="梯度下降" scheme="http://mantoudev.com/tags/%E6%A2%AF%E5%BA%A6%E4%B8%8B%E9%99%8D/"/>
</entry>
<entry>
<title>[机器学习Lesson 2]代价函数之线性回归算法</title>
<link href="http://mantoudev.com/%5B%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0Lesson%202%5D%E4%BB%A3%E4%BB%B7%E5%87%BD%E6%95%B0%E4%B9%8B%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92%E7%AE%97%E6%B3%95/"/>
<id>http://mantoudev.com/[机器学习Lesson 2]代价函数之线性回归算法/</id>
<published>2018-03-26T15:33:00.000Z</published>
<updated>2018-11-27T14:33:45.190Z</updated>
<content type="html"><![CDATA[<blockquote><p>本章内容主要是介绍:单变量线性回归算法(Linear regression with one variable)</p></blockquote><h2 id="1-线性回归算法(linear-regression)"><a href="#1-线性回归算法(linear-regression)" class="headerlink" title="1. 线性回归算法(linear regression)"></a>1. 线性回归算法(linear regression)</h2><h3 id="1-1-预测房屋价格"><a href="#1-1-预测房屋价格" class="headerlink" title="1.1 预测房屋价格"></a>1.1 预测房屋价格</h3><p>下图是俄勒冈州波特兰市的住房价格和面积大小的关系:<br><a id="more"></a></p><p><img src="https://s1.ax2x.com/2018/03/25/15HwS.png" alt="数据集包含俄勒冈州波特兰市的住房价格"></p><p>该问题属于监督学习中的回归问题,让我们来复习一下:</p><ul><li>监督学习(Supervised’Learning’):对示例数据给出“正确答案”。<ul><li>回归问题(Regression ‘Problem’):根据之前的数据预测出一个准确的输出值 。</li></ul></li></ul><h3 id="1-2-训练集"><a href="#1-2-训练集" class="headerlink" title="1.2 训练集"></a>1.2 训练集</h3><p><img src="https://s1.ax2x.com/2018/03/25/15bGR.png" alt="image"></p><ul><li><strong>m</strong>=训练样本数量</li><li><strong>x’s</strong>=输入变量/特征量</li><li><strong>y’s</strong>=输出变量/目标变量,预测结果</li></ul><p>(x,y)表示一个训练样本。</p><p>x(1) 指的是 第一个训练集里值为2104的输入值, 这个就是第一行里的x x(2) 等于1416。这是第二个x y(1) 等于460,这是第一个训练集样本的y值, 这就是(1)所代表的含义。</p><p>这就是一个监督学习算法的工作方式,我们可以看到这里有我们的训练集里房屋价格,我们把它喂给我们的学习算法,然后输出一个函数。 </p><p>按照惯例,通常表示为小写h代表hypothesis(假设) h表示一个函数。输入是房屋尺寸大小,就像你朋友想出售的房屋。因此,h 根据输入的 x 值来得出 y 值。 y值对应房子的价格。所以h是一个从x到y的函数映射 。</p><ul><li>y关于x的线性函数 :</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hθ(x)=θ0+θ1*x</span><br></pre></td></tr></table></figure><p><img src="https://s1.ax2x.com/2018/03/27/1Uj5p.png" alt="image"></p><p>这个模型被称为<code>线性回归(linear regression)模型</code>。 这实际上是关于单个变量的线性回归,这个变量就是x 根据x来预测所有的价格函数。同时, 对于这种模型有另外一个名称,称作<code>单变量线性回归</code> 单变量是对一个变量的一种特别的表述方式。总而言之 这就是线性回归。</p><h2 id="2-代价函数-Cost-Function"><a href="#2-代价函数-Cost-Function" class="headerlink" title="2. 代价函数(Cost Function)"></a>2. 代价函数(Cost Function)</h2><p>任何能够衡量模型预测出来的值h(θ)与真实值y之间的差异的函数都可以叫做代价函数C(θ),如果有多个样本,则可以将所有代价函数的取值求均值,记做J(θ)。</p><p><code>J(θ0,θ1)=12m$\sum$i=1m(y^i−yi)2=12m∑i=1m(hθ(xi)−yi)2</code></p><p><img src="https://s1.ax2x.com/2018/03/27/1Um0y.md.png" alt="image"></p><ul><li><p>m:训练样本的个数;</p></li><li><p>hθ(x):用参数θ和x预测出来的y值;</p></li><li><p>y:原训练样本中的y值,也就是标准答案</p></li><li><p>上角标(i):第i个样本</p></li></ul><h2 id="3-代价函数1-简化版-当θ0-0时"><a href="#3-代价函数1-简化版-当θ0-0时" class="headerlink" title="3. 代价函数1(简化版):当θ0=0时"></a>3. 代价函数1(简化版):当θ0=0时</h2><p>hθ(x)=θ1x,如下图:</p><h5 id="重要公式"><a href="#重要公式" class="headerlink" title="重要公式"></a>重要公式</h5><p><img src="https://s1.ax2x.com/2018/03/26/1aftG.md.png" alt="image"></p><ul><li>Hypothesis: 假设。这个例子中是尺寸对于房价关系的预测。</li><li>Parameters: 参数。</li><li>Cost Function:代价函数。</li><li>Goal: 优化目标。代价最小化。</li></ul><h3 id="3-1-斜率为1时的代价函数"><a href="#3-1-斜率为1时的代价函数" class="headerlink" title="3.1 斜率为1时的代价函数"></a>3.1 斜率为1时的代价函数</h3><p><img src="https://s1.ax2x.com/2018/03/26/1aoPz.png" alt="image"></p><h5 id="(1)假设函数"><a href="#(1)假设函数" class="headerlink" title="(1)假设函数"></a>(1)假设函数</h5><blockquote><p>x轴为面积,y轴为房价 </p></blockquote><p>假设函数 h(x) 对于一个固定的θ1,这是一个关于x 的函数。 所以这个假设函数就是一个关于 x 这个房子大小的函数。</p><h5 id="(2)代价函数"><a href="#(2)代价函数" class="headerlink" title="(2)代价函数"></a>(2)代价函数</h5><blockquote><p>x轴为假设函数的斜率,y即代价大小</p></blockquote><p>代价函数 J 是一个关于参数 θ1 的函数,而 θ1 控制着这条直线的斜率 。</p><h3 id="3-2-斜率为0-5时的代价函数"><a href="#3-2-斜率为0-5时的代价函数" class="headerlink" title="3.2 斜率为0.5时的代价函数"></a>3.2 斜率为0.5时的代价函数</h3><p><img src="https://s1.ax2x.com/2018/03/26/1aiwn.png" alt="image"></p><p>斜率为0.5时,取3个样本(m=3):(0.5,1),(1,2),(1.5,3)。套公式得出J(0.5)=0.58<br>同理,J(0)=1/6(1²+2²+3²)=14/6,求出更多的点之后,我们得出类似以下函数:</p><p><img src="https://s1.ax2x.com/2018/03/27/1en09.png" alt="image"></p><p>学习算法的优化目标是我们想找到一个 θ1 的值,来将 J(θ1) 最小化。这是我们线性回归的目标函数。 上面的曲线中,让 J(θ1) 最小化的值是 θ1=1。这个确实就对应着最佳的通过了数据点的拟合直线 。这条直线就是由 θ1=1 的设定而得到的。 对于这个特定的训练样本,我们最后能够完美地拟合 这就是为什么最小化 J(θ1),对应着寻找一个最佳拟合直线的目标。</p><h2 id="4-代价函数2-完整版"><a href="#4-代价函数2-完整版" class="headerlink" title="4. 代价函数2:完整版"></a>4. 代价函数2:完整版</h2><p>包含θ0、θ1两个参数的代价函数呈现出来的是类似下图的三维曲面图,两个轴分别表示θ0、θ1。</p><p><img src="https://s1.ax2x.com/2018/03/26/1rDX6.png" alt="image"></p><p>在ML中,一般使用轮廓图( contour plot 或 contour figure 的意思)描述该模型。</p><h3 id="4-1-轮廓图简介"><a href="#4-1-轮廓图简介" class="headerlink" title="4.1 轮廓图简介"></a>4.1 轮廓图简介</h3><p><img src="https://s1.ax2x.com/2018/03/26/1r7za.png" alt="image"></p><p>右侧图形就是一个轮廓图,两个轴分别表示θ0和θ1。 而这些一圈一圈的椭圆形,每一个圈就表示J(θ0,θ1) 相同的所有点的集合。</p><p>如图选取三个点,这三个点都表示相同的 J(θ0,θ1) 的值。横纵坐标分别是θ0, θ1 这三个点的 J(θ0,θ1) 值是相同的。我们需要算的代价函数即为圆心的点,此时我们的代价最小。</p><h3 id="4-2-第一组数据"><a href="#4-2-第一组数据" class="headerlink" title="4.2 第一组数据"></a>4.2 第一组数据</h3><p> 我们选取一组数据,<code>θ0=800</code>,<code>θ1=-0.15</code>,此时我们可以对应得到一个左边这样一条线。</p><p> <img src="https://s1.ax2x.com/2018/03/26/1rdmz.png" alt="image"></p><p>以这组 θ0,θ1 为参数的这个假设 h(x) 并不是数据的较好拟合。并且你也发现了这个代价值 距离最小值点还很远。也就是说这个代价值还是算比较大的,因此不能很好拟合数据。</p><h3 id="4-3-第二组数据"><a href="#4-3-第二组数据" class="headerlink" title="4.3 第二组数据"></a>4.3 第二组数据</h3><p><img src="https://s1.ax2x.com/2018/03/27/1eetp.png" alt="选取第二组数据"></p><p><code>θ0=360</code>,<code>θ1=0</code>。我们可以得到<code>h(x)=360+0*x</code>这样一条直线。同样不能很好的拟合数据。</p><h3 id="4-4-第三组数据"><a href="#4-4-第三组数据" class="headerlink" title="4.4 第三组数据"></a>4.4 第三组数据</h3><p>最后一个例子:<br><img src="https://s1.ax2x.com/2018/03/27/1ex3h.md.png" alt="image"></p><p>这个点其实不是最小值,但已经非常靠近最小值点了。 这个点对数据的拟合就很不错,它对应这样两个θ0 和 θ1 的值。同时也对应这样一个 h(x) 这个点虽然不在最小值点,但非常接近了。 因此误差平方和,或者说 训练样本和假设的距离的平方和,这个距离值的平方和 非常接近于最小值,尽管它还不是最小值。</p><h2 id="5-小结"><a href="#5-小结" class="headerlink" title="5. 小结"></a>5. 小结</h2><p>通过这些图形,本篇文章主要是帮助理解这些代价函数 J 所表达的值;它们是什么样的它们对应的假设是什么样的;以及什么样的假设对应的点更接近于代价函数J的最小值。</p><p>我们真正需要的是一种有效的算法,能够自动地找出这些使代价函数J取最小值的参数θ0和θ1来。我们也不希望编个程序 把这些点画出来,然后人工的方法来读出这些点的数值,这很明显不是一个好办法。 </p><p>事实上在深入机器学习的过程中, 我们会遇到更复杂、更高维度、更多参数的情况。而这些情况是很难画出图的,因此更无法将其可视化,因此我们真正需要的,是编写程序来找出这些最小化代价函数的θ0和θ1的值。在后续文章中将介绍一种算法 能够自动地找出能使代价函数 J最小化的参数θ0和θ1的值。</p><hr><p>本文资料部分来源于吴恩达 (Andrew Ng) 博士的斯坦福大学机器学习公开课视频教程。 </p><p>[1]网易云课堂机器学习课程:<br><a href="http://open.163.com/special/opencourse/machinelearning.html" target="_blank" rel="noopener">http://open.163.com/special/opencourse/machinelearning.html</a><br>[2]coursera课程:<br><a href="https://www.coursera.org/learn/machine-learning/" target="_blank" rel="noopener">https://www.coursera.org/learn/machine-learning/</a></p>]]></content>
<summary type="html">
<blockquote>
<p>本章内容主要是介绍:单变量线性回归算法(Linear regression with one variable)</p>
</blockquote>
<h2 id="1-线性回归算法(linear-regression)"><a href="#1-线性回归算法(linear-regression)" class="headerlink" title="1. 线性回归算法(linear regression)"></a>1. 线性回归算法(linear regression)</h2><h3 id="1-1-预测房屋价格"><a href="#1-1-预测房屋价格" class="headerlink" title="1.1 预测房屋价格"></a>1.1 预测房屋价格</h3><p>下图是俄勒冈州波特兰市的住房价格和面积大小的关系:<br>
</summary>
<category term="机器学习" scheme="http://mantoudev.com/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="机器学习" scheme="http://mantoudev.com/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="线性回归" scheme="http://mantoudev.com/tags/%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/"/>
</entry>
<entry>
<title>[机器学习Lesson 1] 机器学习简介</title>
<link href="http://mantoudev.com/%5B%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0Lesson%201%5D%20%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E7%AE%80%E4%BB%8B/"/>
<id>http://mantoudev.com/[机器学习Lesson 1] 机器学习简介/</id>
<published>2018-03-26T02:03:00.000Z</published>
<updated>2018-11-27T14:33:40.064Z</updated>
<content type="html"><![CDATA[<h2 id="1-Machine-Learning-definition(机器学习定义)"><a href="#1-Machine-Learning-definition(机器学习定义)" class="headerlink" title="1. Machine Learning definition(机器学习定义)"></a>1. Machine Learning definition(机器学习定义)</h2><ul><li><p>Arthur Samuel(1959年)将机器学习非正式定义为:在不直接针对问题进行编程的情况下,赋予计算机学习能力的一个研究领域。<br>创造西洋棋程序,可以和自己对战。</p></li><li><p>Tom Mitchell(1998年)提出一个更为正式关于机器学习的定义 :对于一个计算机程序来说:给它一个任务T和一个性能测量方法P,如果在经验E的影响下,P对T的测量结果得到了改进,那么就说改程序从E中学习。</p><a id="more"></a></li></ul><p>E = the experience of playing many games of checkers</p><p>T = the task of playing checkers.</p><p>P = the probability that the program will win the next game.</p><h2 id="2-Supervised-Learning-监督学习"><a href="#2-Supervised-Learning-监督学习" class="headerlink" title="2. Supervised Learning (监督学习)"></a>2. Supervised Learning (监督学习)</h2><p> 它被称作监督学习是因为对于每个数据来说 我们给出了 “正确的答案”。<br>你有一些问题和他们的答案,你要做的有监督学习就是学习这些已经知道答案的问题。然后你就具备了经验了,这就是学习的成果。然后在你接受到一个新的不知道答案的问题的时候,你可以根据学习得到的经验,得出这个新问题的答案。(试想一下高考不正是这样,好的学习器就能有更强的做题能力,考好的分数,上好的大学…..)。我们有一个样本数据集,如果对于每一个单一的数据根据它的特征向量我们要去判断它的标签(算法的输出值),那么就是有监督学习。通俗的说,有监督学习就是比无监督学习多了一个可以表达这个数据特质的标签。</p><p>包含回归(Regression)和分类(Classfication)。</p><ul><li>举例:<ol><li>房价 与 面积的关系</li></ol></li></ul><h4 id="2-1-Classfication-分类任务"><a href="#2-1-Classfication-分类任务" class="headerlink" title="2.1 Classfication (分类任务)"></a>2.1 Classfication (分类任务)</h4><p>离散变量预测,设定了标准答案,复合条件,是或否。</p><p><img src="https://upload-images.jianshu.io/upload_images/4090284-20697a8e0a15ac5d.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/700" alt="image"></p><ul><li><p>举例:</p><ol><li>肿瘤良性/恶性 与 肿瘤大小的关系。(0或1结构)</li><li>年纪 与 肿瘤大小关系。(聚合结构)</li><li>预测明天的气温是多少度</li></ol></li><li><p>Support Vector machines(支持向量机的算法):可以吧数据映射到无限维空间中。</p></li><li><p>问题: </p><ol><li>如何把一个无限维的向量映射到计算机内存中? </li><li>如何表示一个无限纬空间中的点?</li></ol></li></ul><h4 id="2-2-Regression(回归任务)"><a href="#2-2-Regression(回归任务)" class="headerlink" title="2.2 Regression(回归任务)"></a>2.2 Regression(回归任务)</h4><p>连续变量预测。</p><p><img src="https://upload-images.jianshu.io/upload_images/4090284-217ab4bb24b34b9e.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/700" alt="image"></p><ul><li>举例:<ol><li>预测明天的气温是多少度。</li></ol></li></ul><h2 id="3-Unsupervised-Learning-无监督学习"><a href="#3-Unsupervised-Learning-无监督学习" class="headerlink" title="3. Unsupervised Learning(无监督学习)"></a>3. Unsupervised Learning(无监督学习)</h2><p> 数据聚合、分类。</p><p> <img src="https://upload-images.jianshu.io/upload_images/4090284-f45f90e71dc0c70e.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/700" alt="image"></p><p>我们有一些问题,但是不知道答案,我们要做的无监督学习就是按照他们的性质把他们自动地分成很多组,每组的问题是具有类似性质的(比如数学问题会聚集在一组,英语问题会聚集在一组,物理……..)。</p><p>所有数据只有特征向量没有标签,但是可以发现这些数据呈现出聚群的结构,本质是一个相似的类型的会聚集在一起。把这些没有标签的数据分成一个一个组合,就是聚类(Clustering)。比如Google新闻,每天会搜集大量的新闻,然后把它们全部聚类,就会自动分成几十个不同的组(比如娱乐,科技,政治……),每个组内新闻都具有相似的内容结构。</p><ul><li>举例:<ol><li>提供一组数据,不提供任何数据的正确答案,你能否在这组数据中寻找到一些有趣的数据结构?</li><li>基因数据分组。</li><li>聚合算法处理图像,对像素数据进行聚合分组,得到类似素描的效果,等效表达。</li><li>图像处理,将图像分成不同区域,像素分到不同区域。创建3D模型,创造类似AR的效果。</li><li>计算机集群,社交网络分析,市场划分,航天数据分析。</li></ol></li></ul><h4 id="3-1-Cocktail-party-problem-鸡尾酒会问题"><a href="#3-1-Cocktail-party-problem-鸡尾酒会问题" class="headerlink" title="3.1 Cocktail party problem(鸡尾酒会问题)"></a>3.1 Cocktail party problem(鸡尾酒会问题)</h4><p>假设我们在参加一个鸡尾酒会,有很多人参加,在环境嘈杂,很多人说话的情况下,能否把感兴趣的某个人的声音单独从嘈杂的背景音中提取出来?<br>规律:不同麦克风收集到说话者声音大小不一样。</p><ul><li>算法A<br>将人声从人声中分离</li><li>独立组件分析<br>将人声从音乐中分离</li></ul><p>其他应用:</p><ul><li>文本处理</li><li>理解功能分级</li></ul><p>使用MATLAB一行代码实现以上算法。</p><h4 id="3-2-ICA-algorithm"><a href="#3-2-ICA-algorithm" class="headerlink" title="3.2 ICA algorithm"></a>3.2 ICA algorithm</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[W,s,v] = svd((repmat(sum(x.*x,1),size(x,1),1).*x)*x');</span><br></pre></td></tr></table></figure><h2 id="4-Reinforcement-Learning-强化算法学习"><a href="#4-Reinforcement-Learning-强化算法学习" class="headerlink" title="4. Reinforcement Learning(强化算法学习)"></a>4. Reinforcement Learning(强化算法学习)</h2><blockquote><p>基本概念是一个被称为 回报函数的概念。<br>使用在不需要进行一次决策的情形中。</p></blockquote><ul><li>举例<ol><li>使用监督学习进行癌症预测,预测一个病人肿瘤是否为恶性。你的预测决定了病人是生死。通过决策产生一个结论,要么对,要么错。</li></ol></li></ul><p>在强化学习问题中,通常会一段时间内做出一系列的决策</p><ul><li>举例<ol><li>自动直升机:给你自动直升机的钥匙,能否写个程序让它飞起来?如果做了一个坏的决策,飞机可能不会马上摔下来,只有你连续做出很多坏的决策时,飞机才会摔下来。相反的,只要连续的做出正确的决策,飞机就可以飞起来了。</li><li>训狗,正确奖励;错误惩罚。</li><li>机器人领域。</li></ol></li></ul>]]></content>
<summary type="html">
<h2 id="1-Machine-Learning-definition(机器学习定义)"><a href="#1-Machine-Learning-definition(机器学习定义)" class="headerlink" title="1. Machine Learning definition(机器学习定义)"></a>1. Machine Learning definition(机器学习定义)</h2><ul>
<li><p>Arthur Samuel(1959年)将机器学习非正式定义为:在不直接针对问题进行编程的情况下,赋予计算机学习能力的一个研究领域。<br>创造西洋棋程序,可以和自己对战。</p>
</li>
<li><p>Tom Mitchell(1998年)提出一个更为正式关于机器学习的定义 :对于一个计算机程序来说:给它一个任务T和一个性能测量方法P,如果在经验E的影响下,P对T的测量结果得到了改进,那么就说改程序从E中学习。</p>
</summary>
<category term="机器学习" scheme="http://mantoudev.com/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="机器学习" scheme="http://mantoudev.com/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
</entry>
<entry>
<title>Git Workflow简介</title>
<link href="http://mantoudev.com/Git%20Workflow%E7%AE%80%E4%BB%8B/"/>
<id>http://mantoudev.com/Git Workflow简介/</id>
<published>2017-01-21T04:00:00.000Z</published>
<updated>2018-11-27T08:48:02.252Z</updated>
<content type="html"><![CDATA[<h2 id="1-Git-WorkFlow介绍"><a href="#1-Git-WorkFlow介绍" class="headerlink" title="1. Git WorkFlow介绍"></a>1. Git WorkFlow介绍</h2><p>Git Flow是构建在Git之上的一个组织软件开发活动的模型,是在Git之上构建的一项软件开发最佳实践。Git Flow是一套使用Git进行源代码管理时的一套行为规范和简化部分Git操作的工具。<br><a id="more"></a></p><p>2010年5月,在一篇名为“一种成功的Git分支模型”的博文中,@nvie介绍了一种在Git之上的软件开发模型。通过利用Git创建和管理分支的能力,为每个分支设定具有特定的含义名称,并将软件生命周期中的各类活动归并到不同的分支上。实现了软件开发过程不同操作的相互隔离。这种软件开发的活动模型被nwie称为“Git Flow”。</p><p>一般而言,软件开发模型有常见的瀑布模型、迭代开发模型、以及最近出现的敏捷开发模型等不同的模型。每种模型有各自应用场景。Git Flow重点解决的是由于源代码在开发过程中的各种冲突导致开发活动混乱的问题。因此,Git flow可以很好的于各种现有开发模型相结合使用。</p><p><img src="https://s1.ax1x.com/2018/01/07/peUfzD.jpg" alt="image"></p><h2 id="2-Git-VS-SVN"><a href="#2-Git-VS-SVN" class="headerlink" title="2. Git VS SVN"></a>2. Git VS SVN</h2><table><thead><tr><th>SVN</th><th>Git</th></tr></thead><tbody><tr><td>分布式管理</td><td>集中式管理</td></tr><tr><td>元数据存储</td><td>文件存储</td></tr><tr><td>offline log</td><td>online log</td></tr><tr><td>有本地分支</td><td>无本地分支</td></tr><tr><td>没有全局版本号</td><td>有全局版本号</td></tr><tr><td>内容完整性(SHA-1)</td><td>N/A</td></tr><tr><td>github,gitlab等配套</td><td>N/A</td></tr></tbody></table><h2 id="3-分支"><a href="#3-分支" class="headerlink" title="3.分支"></a>3.分支</h2><h3 id="3-1-历史分支(Master-Develop)"><a href="#3-1-历史分支(Master-Develop)" class="headerlink" title="3.1 历史分支(Master , Develop)"></a>3.1 历史分支(Master , Develop)</h3><p>Gitflow工作流使用2个分支来记录项目的历史。master分支存储了正式发布的历史,而develop分支作为功能的集成分支。 这样也方便master分支上的所有提交分配一个版本号。<br><img src="https://s1.ax1x.com/2018/01/07/peU4Qe.jpg" alt="历史分支"></p><h3 id="3-2-功能分支(Feature)"><a href="#3-2-功能分支(Feature)" class="headerlink" title="3.2 功能分支(Feature)"></a>3.2 功能分支(Feature)</h3><p>每个新功能位于一个自己的分支,这样可以push到中央仓库以备份和协作。 但功能分支不是从master分支上拉出新分支,而是使用develop分支作为父分支。当新功能完成时,合并回develop分支。 新功能提交应该从不直接与master分支交互。</p><p><img src="https://s1.ax1x.com/2018/01/07/peU5sH.jpg" alt="功能分支"></p><h3 id="3-3-发布分支(Release)"><a href="#3-3-发布分支(Release)" class="headerlink" title="3.3 发布分支(Release)"></a>3.3 发布分支(Release)</h3><p>一旦develop分支上有了做一次发布(或者说快到了既定的发布日)的足够功能:本期要发布的所有功能已开发完成,测试通过。就从develop分支上fork一个release发布分支。 release分支用于开始发布循环,所以从这个时间点开始之后新的功能不能再加到这个分支上—— 这个分支只应该做Bug修复、文档生成和其它面向发布任务。 一旦对外发布的工作都完成了,发布分支合并到master分支并分配一个版本号打好Tag。 另外,这些从新建发布分支以来的做的修改要合并回develop分支。</p><p>使用一个用于发布准备的专门分支,使得一个团队可以在完善当前的发布版本的同时,另一个团队可以继续开发下个版本的功能。 这也打造定义良好的开发阶段(比如,可以很轻松地说,『这周我们要做准备发布版本4.0』,并且在仓库的目录结构中可以实际看到)。</p><p><img src="https://s1.ax1x.com/2018/01/07/peUTeA.jpg" alt="发布分支"></p><h3 id="3-4-维护分支(Hotfix)"><a href="#3-4-维护分支(Hotfix)" class="headerlink" title="3.4 维护分支(Hotfix)"></a>3.4 维护分支(Hotfix)</h3><p>维护分支或说是热修复(hotfix)分支用于生成快速给产品发布版(production releases)打补丁,这是唯一可以直接从master分支fork出来的分支。 修复完成,修改应该马上合并回master分支和develop分支(当前的发布分支),master分支应该用新的版本号打好Tag。</p><p>为Bug修复使用专门分支,让团队可以处理掉问题而不用打断其它工作或是等待下一个发布循环。 你可以把维护分支想成是一个直接在master分支上处理的临时发布。</p><p><img src="https://s1.ax1x.com/2018/01/07/peUHot.jpg" alt="维护分支"></p><h2 id="4-实际"><a href="#4-实际" class="headerlink" title="4. 实际"></a>4. 实际</h2><ul><li><p>初始化</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git flow init</span><br></pre></td></tr></table></figure></li><li><p>开发一个功能</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git flow feature start <your feature></span><br><span class="line">git flow feature finish <your feature></span><br></pre></td></tr></table></figure></li><li><p>完成开发一个功能</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git flow feature publish <name></span><br><span class="line">git flow feature pull <remote> <name></span><br></pre></td></tr></table></figure></li><li><p>发布版本</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git flow release start <release></span><br><span class="line">git flow release finish <release></span><br></pre></td></tr></table></figure></li><li><p>修补bug </p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git flow hotfix start <release></span><br><span class="line">git flow hotfix finish <release></span><br></pre></td></tr></table></figure></li></ul><h2 id="5-常用命令"><a href="#5-常用命令" class="headerlink" title="5.常用命令"></a>5.常用命令</h2><p>创建分支: <code>git branch mybranch</code><br>切换分支: <code>git checkout mybranch</code><br>创建并切换分支: <code>git checkout -b mybranch</code><br>更新master主线上的东西到该分支上:<code>git rebase master</code><br>切换到master分支:<code>git checkout master</code><br>更新mybranch分支上的东西到master上:<code>git rebase mybranch</code><br>提交:<code>git commit -a</code><br>对最近一次commit的进行修改:<code>git commit -a –amend</code><br>commit之后,如果想撤销最近一次提交(即退回到上一次版本)并本地保留代码:<code>git reset HEAD^</code><br>合并分支:(merge from) <code>git checkout master</code><br>$ git merge mybranch (merge from mybranch)<br>删除分支: <code>git branch -d mybranch</code><br>强制删除分支: <code>git branch -D mybranch</code><br>列出所有分支: <code>git branch</code><br>查看各个分支最后一次提交: <code>git branch -v</code><br>查看哪些分支合并入当前分支: <code>git branch –merged</code><br>查看哪些分支未合并入当前分支: <code>git branch –no-merged</code><br>更新远程库到本地: <code>git fetch origin</code><br>推送分支: <code>git push origin mybranch</code><br>取远程分支合并到本地: <code>git merge origin/mybranch</code><br>取远程分支并分化一个新分支: <code>git checkout -b mybranch origin/mybranch</code> </p><h2 id="6-学习资料推荐"><a href="#6-学习资料推荐" class="headerlink" title="6. 学习资料推荐"></a>6. 学习资料推荐</h2><ol><li><a href="https://github.com/xirong/my-git" target="_blank" rel="noopener">Git的资料整理</a></li><li><a href="https://git-scm.com/book/zh/v2" target="_blank" rel="noopener">Pro Git book</a></li><li><a href="http://backlogtool.com/git-guide/cn/" target="_blank" rel="noopener">猴子都能懂的Git入门系列</a></li></ol>]]></content>
<summary type="html">
<h2 id="1-Git-WorkFlow介绍"><a href="#1-Git-WorkFlow介绍" class="headerlink" title="1. Git WorkFlow介绍"></a>1. Git WorkFlow介绍</h2><p>Git Flow是构建在Git之上的一个组织软件开发活动的模型,是在Git之上构建的一项软件开发最佳实践。Git Flow是一套使用Git进行源代码管理时的一套行为规范和简化部分Git操作的工具。<br>
</summary>
<category term="Git" scheme="http://mantoudev.com/categories/Git/"/>
<category term="Git" scheme="http://mantoudev.com/tags/Git/"/>
</entry>
<entry>
<title>Git常用命令速查</title>
<link href="http://mantoudev.com/Git%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E9%80%9F%E6%9F%A5/"/>
<id>http://mantoudev.com/Git常用命令速查/</id>
<published>2016-12-01T04:00:00.000Z</published>
<updated>2018-11-27T08:49:02.314Z</updated>
<content type="html"><![CDATA[<h1 id="Alias"><a href="#Alias" class="headerlink" title="Alias"></a>Alias</h1><p>下面的只是例子,想改成什么跟随自己的意愿即可。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git config --global alias.st status //status 缩写成 st</span><br><span class="line">git config --global alias.co checkout //checkout 缩写成 co</span><br><span class="line">git config --global alias.br branch //branch 缩写成 br</span><br><span class="line">git config --global alias.ci commit //commit 缩写成 ci</span><br><span class="line">git config --global alias.lg <span class="string">"log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"</span></span><br></pre></td></tr></table></figure></p><a id="more"></a><p>如果不想使用了,删除掉的话,直接删除 conf 配置文件中的行即可,global 的在当前用户下<code>vim ~/.gitconfig</code> 删除<code>alias</code>下你配置的内容接口;若是当前仓库则在 <code>.git/config</code> 中。</p><h1 id="Git-Config"><a href="#Git-Config" class="headerlink" title="Git Config"></a>Git Config</h1><p>Git 配置文件分为三级,系统级(–system)、用户级(–global)和目录级(–local),三者的使用优先级以离目录 (repository)最近为原则,如果三者的配置不一样,则生效优先级 <strong>目录级>用户级>系统级</strong>,可以通过 <code>git config --help</code> 查看更多内容。</p><ul><li>系统级配置存储在 <code>/etc/gitconfig</code> 文件中,可以使用 <code>git config --system user.name "jim"</code> ,<code>git config --sytem user.email "[email protected]"</code> 来进行配置,该配置对系统上所有用户及他们所拥有的仓库都生效的配置值。</li><li>用户级存储在每个用户的 <code>~/.gitconfig</code> 中,可以使用 <code>git config --global user.name "jim"</code> ,<code>git config --global user.email "[email protected]"</code> 来进行配置,该配置对当前用户上所有的仓库有效。</li><li>目录级存储在每个仓库下的 <code>.git/config</code> 中,可以使用 <code>git config --local user.name "jim"</code> , <code>git config --local user.email "[email protected]"</code> 来进行配置,只对当前仓库生效。</li></ul><h1 id="Basic-Usage"><a href="#Basic-Usage" class="headerlink" title="Basic Usage"></a>Basic Usage</h1><ul><li>添加文件到暂存区(staged):<code>git add filename</code> / <code>git stage filename</code></li><li>将所有修改文件添加到暂存区(staged): <code>git add --all</code> / <code>git add -A</code></li><li>提交修改到暂存区(staged):<code>git commit -m 'commit message'</code> / <code>git commit -a -m 'commit message'</code> 注意理解 -a 参数的意义</li><li>从Git仓库中删除文件:<code>git rm filename</code></li><li>从Git仓库中删除文件,但本地文件保留:<code>git rm --cached filename</code></li><li>重命名某个文件:<code>git mv filename newfilename</code> 或者直接修改完毕文件名 ,进行<code>git add -A && git commit -m 'commit message'</code> Git会自动识别是重命名了文件</li><li>获取远程最新代码到本地:<code>git pull (origin branchname)</code> 可以指定分支名,也可以忽略。pull 命令自动 fetch 远程代码并且 merge,如果有冲突,会显示在状态栏,需要手动处理。更推荐使用:<code>git fetch</code> 之后 <code>git merge --no-ff origin branchname</code> 拉取最新的代码到本地仓库,并手动 merge 。</li></ul><h1 id="Repository"><a href="#Repository" class="headerlink" title="Repository"></a>Repository</h1><ul><li>检出(clone)仓库代码:<code>git clone repository-url</code> / <code>git clone repository-url local-directoryname</code><ul><li>例如,clone jquery 仓库到本地: <code>git clone git://github.com/jquery/jquery.git</code></li><li>clone jquery 仓库到本地,并且重命名为 my-jquery :<code>git clone git://github.com/jquery/jquery.git my-jquery</code></li></ul></li><li>查看远程仓库:<code>git remote -v</code></li><li>添加远程仓库:<code>git remote add [name] [repository-url]</code></li><li>删除远程仓库:<code>git remote rm [name]</code></li><li>修改远程仓库地址:<code>git remote set-url origin new-repository-url</code></li><li>拉取远程仓库: <code>git pull [remoteName] [localBranchName]</code></li><li>推送远程仓库: <code>git push [remoteName] [localBranchName]</code> 例: <code>git push -u orgin master</code> 将当前分支推送到远端master分支</li><li>将本地 test 分支提交到远程 master 分支: <code>git push origin test:master</code> (把本地的某个分支 test 提交到远程仓库,并作为远程仓库的 master 分支) 提交本地 test 分支作为远程的 test 分支 :<code>git push origin test:test</code></li></ul><h1 id="Checkout"><a href="#Checkout" class="headerlink" title="Checkout"></a>Checkout</h1><p>checkout命令用于从历史提交(或者暂存区域)中拷贝文件到工作目录,也可用于切换分支。<br><img src="./_image/2016-07-14 21-26-37.jpg?r=49" alt=""> <img src="./_image/2016-07-14 21-15-47.jpg?r=49&f=2" alt=""><br><strong>匿名分支</strong>:如果既没有指定文件名,也没有指定分支名,而是一个标签、远程分支、SHA-1值或者是像 master~3 类似的东西,就得到一个匿名分支,称作 detached HEAD(被分离的 HEAD 标识)。</p><p><img src="./_image/2016-07-14 21-44-06.jpg?r=56" alt=""></p><p>当HEAD处于分离状态(不依附于任一分支)时,提交操作可以正常进行,但是不会更新任何已命名的分支。(你可以认为这是在更新一个匿名分支。)一旦此后你切换到别的分支,比如说 master,那么这个提交节点(可能)再也不会被引用到,然后就会被丢弃掉了。注意这个命令之后就不会有东西引用 2eecb。详细查看:<a href="http://marklodato.github.io/visual-git-guide/index-zh-cn.html#detached" target="_blank" rel="noopener">visual-git-guide#detached</a><br>但是,如果你想保存这个状态,可以用命令 <code>git checkout -b name</code> 来创建一个新的分支。<br><img src="./_image/2016-07-14 21-45-50.jpg?r=56" alt=""></p><h1 id="Log"><a href="#Log" class="headerlink" title="Log"></a>Log</h1><blockquote><p>Description : Shows the commit logs.<br>The command takes options applicable to the git rev-list command to control what is shown and how, and options applicable to the git diff-* commands to control how the changes each commit introduces are shown.<br>git log [options] [revision range] [path]</p></blockquote><p>常用命令整理如下:</p><ul><li>查看日志:<code>git log</code></li><li>查看日志,并查看每次的修改内容:<code>git log -p</code></li><li>查看日志,并查看每次文件的简单修改状态:<code>git log --stat</code></li><li>一行显示日志:<code>git log --pretty=oneline</code> / <code>git log --pretty='format:"%h - %an, %ar : %s'</code></li><li>查看日志范围:<ul><li>查看最近10条日志:<code>git log -10</code></li><li>查看2周前:<code>git log --until=2week</code> 或者指定2周的明确日期,比如:<code>git log --until=2015-08-12</code></li><li>查看最近2周内:<code>git log --since=2week</code> 或者指定2周明确日志,比如:<code>git log --since=2015-08-12</code></li><li>只查看某个用户的提交:<code>git log --committer=user.name</code> / <code>git log --author=user.name</code></li><li>只查看提交msg中包含某个信息的历史,比如包含’测试’两个字的:<code>git log --grep '测试'</code></li><li>试试这个 : <code>git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit</code> 感觉好用就加成 alias ,方便日后用,方法:<code>git config --global alias.aliasname 'alias-content'</code></li><li>更多用法:<a href="http://git-scm.com/book/en/v2/Git-Basics-Viewing-the-Commit-History" target="_blank" rel="noopener">Viewing the History – 《Pro Git2》</a></li></ul></li></ul><p><code>log</code> 的目的就是为了查看改动点来排查问题,除了 <code>git log</code> 还可以使用 <code>git show</code> 、<code>git blame</code> 来查看文件的改动。</p><ul><li>Who changed what and when in a file : <code>git blame $file</code></li><li>查看一次 commit 中修改了哪些文件: <code>git show --pretty="" --name-only <sha1-of-commit></code> 或者 <code>git diff-tree --no-commit-id --name-only -r <sha1-of-commit></code></li></ul><h1 id="Undo-things"><a href="#Undo-things" class="headerlink" title="Undo things"></a>Undo things</h1><ul><li>上次提交 msg 错误/有未提交的文件应该同上一次一起提交,需要重新提交备注:<code>git commit --amend -m 'new msg'</code></li><li>修改上次提交的 author、email :<code>git commit --amend --author="newName <newEmail>"</code></li><li>修改整个历史记录中的某些错误的 author、email: <code>git rebase 或者 git filter-branch</code> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment"># git rebase 模式</span></span><br><span class="line"> git rebase -i -p 76892625a7b126f4772f8d7e331ada3552c11ce1</span><br><span class="line"> <span class="comment"># 弹出编辑器,在需要修改的 commit 处 由 picked 改变为 edit ,然后 wq 退出 vim;</span></span><br><span class="line"> git commit --amend --author <span class="string">'newName <newEmail>'</span></span><br><span class="line"> <span class="comment"># 执行后即变更了相应的 author 和 email</span></span><br><span class="line"> git rebase --<span class="built_in">continue</span></span><br><span class="line"> <span class="comment">################################################################</span></span><br><span class="line"> <span class="comment"># git filter-branch 模式 https://help.github.com/articles/changing-author-info/</span></span><br><span class="line">git filter-branch --env-filter <span class="string">'</span></span><br><span class="line"><span class="string">OLD_EMAIL="[email protected]"</span></span><br><span class="line"><span class="string">CORRECT_NAME="Your Correct Name"</span></span><br><span class="line"><span class="string">CORRECT_EMAIL="[email protected]"</span></span><br><span class="line"><span class="string">if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]</span></span><br><span class="line"><span class="string">then</span></span><br><span class="line"><span class="string"> export GIT_COMMITTER_NAME="$CORRECT_NAME"</span></span><br><span class="line"><span class="string"> export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"</span></span><br><span class="line"><span class="string">fi</span></span><br><span class="line"><span class="string">if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]</span></span><br><span class="line"><span class="string">then</span></span><br><span class="line"><span class="string"> export GIT_AUTHOR_NAME="$CORRECT_NAME"</span></span><br><span class="line"><span class="string"> export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"</span></span><br><span class="line"><span class="string">fi</span></span><br><span class="line"><span class="string">'</span> --tag-name-filter cat -- --branches --tags</span><br></pre></td></tr></table></figure></li></ul><p><img src="./_image/2017-06-02-11-51-27.jpg?r=54" alt=""></p><ul><li>一次<code>git add -A</code>后,需要将某个文件撤回到工作区,即:某个文件不应该在本次commit中:<code>git reset HEAD filename</code></li><li>撤销某些文件的修改内容:<code>git checkout -- filename</code> 注意:一旦执行,所有的改动都没有了,谨慎!谨慎!谨慎!</li><li>将工作区内容回退到远端的某个版本:<code>git reset --hard <sha1-of-commit></code></li></ul><h1 id="Reset"><a href="#Reset" class="headerlink" title="Reset"></a>Reset</h1><p>reset命令把当前分支指向另一个位置,并且有选择的变动工作目录和索引,也用来在从历史仓库中复制文件到索引,而不动工作目录。</p><p><img src="./_image/2016-07-14 20-31-39.png?r=64&f=1" alt=""><br>将工作区内容回退到远端的某个版本:<code>git reset --hard <sha1-of-commit></code></p><ul><li><code>git reset --hard HEAD^</code> reset index and working directory ,<commitid> 以来所有的变更全部丢弃,并将 HEAD 指向<commitid></commitid></commitid></li></ul><ul><li><code>git reset --soft HEAD^</code> nothing changed to index and working directory ,仅仅将 HEAD 指向<commitid> ,所有变更显示在 “changed to be committed”中</commitid></li><li><code>git reset --mixed HEAD^</code> default,reset index ,nothing to working directory 默认选项,工作区代码不改动,添加变更到index区</li></ul><h1 id="Revert"><a href="#Revert" class="headerlink" title="Revert"></a>Revert</h1><blockquote><p><code>git revert</code> will create a new commit that’s the opposite (or inverse) of the given SHA. If the old commit is “matter”, the new commit is “anti-matter”—anything removed in the old commit will be added in the new commit and anything added in the old commit will be removed in the new commit.<br>This is Git’s safest, most basic “undo” scenario, because it doesn’t alter history—so you can now git push the new “inverse” commit to undo your mistaken commit.</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git revert [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>…</span><br><span class="line">git revert --<span class="built_in">continue</span></span><br><span class="line">git revert --quit</span><br><span class="line">git revert --abort</span><br></pre></td></tr></table></figure><h2 id="Revert-VS-Reset"><a href="#Revert-VS-Reset" class="headerlink" title="Revert VS Reset"></a>Revert VS Reset</h2><h1 id="Diff"><a href="#Diff" class="headerlink" title="Diff"></a>Diff</h1><ul><li>查看工作区(working directory)和暂存区(staged)之间差异:<code>git diff</code></li><li>查看工作区(working directory)与当前仓库版本(repository)HEAD版本差异:<code>git diff HEAD</code></li><li>查看暂存区(staged)与当前仓库版本(repository)差异:<code>git diff --cached</code> / <code>git diff --staged</code></li><li>不查看具体改动,只查看改动了哪些类:<code>git diff --stat</code></li></ul><h1 id="Merge"><a href="#Merge" class="headerlink" title="Merge"></a>Merge</h1><p><img src="./_image/2016-07-14 20-53-25.jpg?r=80" alt=""></p><ul><li>解决冲突后/获取远程最新代码后合并代码:<code>git merge branchname</code> ,将 branchname 分支上面的代码合并到当前分支</li><li>保留该存在版本合并log:<code>git merge --no-ff branchname</code> 参数 <code>--no-ff</code> 防止 fast-forward 的提交,详情参考:<a href="http://stackoverflow.com/questions/9069061/what-is-the-difference-between-git-merge-and-git-merge-no-ff" target="_blank" rel="noopener">the difference</a>,fast-forward:分支内容一致,指针直接移动,并未能看出分支信息<h1 id="Rebase"><a href="#Rebase" class="headerlink" title="Rebase"></a>Rebase</h1>Rebase 同 Merge 的结果是一样的,就是合并本地、远程的改动,但过程中还有区别。<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git checkout mywork</span><br><span class="line">git rebase origin</span><br></pre></td></tr></table></figure></li></ul><p>这些命令会把你的”mywork”分支里的每个提交(commit)取消掉,并且把它们临时 保存为补丁(patch)(这些补丁 放到”.git/rebase”目录中),然后把”mywork”分支更新 到最新的”origin”分支,最后把保存的这些补丁应用 到”mywork”分支上。<br>一张图分清 rebase 和 merge 的区别</p><p><img src="./_image/2016-07-19 20-35-30.jpg?r=56" alt=""><br>在rebase的过程中,也许会出现冲突(conflict). 在这种情况,Git会停止rebase并会让你去解决冲突;在解决完冲突后,用 <code>git-add</code> 命令去更新这些内容的索引(index), 然后,你无需执行 git-commit,只要执行: <code>git rebase --continue</code> 这样git会继续应用(apply)余下的补丁。在任何时候,你可以用 –abort 参数来终止rebase的行动,并且”mywork” 分支会回到rebase开始前的状态。 <code>git rebase --abort</code></p><h1 id="Cherry-Pick"><a href="#Cherry-Pick" class="headerlink" title="Cherry Pick"></a>Cherry Pick</h1><p>cherry-pick 命令”复制”一个提交节点并在当前分支做一次完全一样的新提交。</p><p><img src="./_image/2016-07-14 20-57-04.jpg?r=65" alt=""></p><h1 id="Branch-workflow"><a href="#Branch-workflow" class="headerlink" title="Branch workflow"></a>Branch workflow</h1><p>Aone2 Git 分支开发部署模型详细解读 <a href="http://docs.alibaba-inc.com:8090/pages/viewpage.action?pageId=194872297" target="_blank" rel="noopener">http://docs.alibaba-inc.com:8090/pages/viewpage.action?pageId=194872297</a></p><p>分支情况 origin</p><ul><li>master</li><li>develop</li><li>release<ul><li>20161129163217010_r_release_yingyongming</li><li>20161029163217010_r_release_yingyongming</li></ul></li><li>feature<ul><li>20161129_163448_newfeature_1</li><li>20161129_163448_newfeature_2</li></ul></li><li>hotfix<ul><li>20161129_163448_hotfix_1</li></ul></li><li>tags<ul><li>20161129163217010_r_release_newfeature_yingyongming<br>创建分支的时候直接操作: <code>git checkout -b feature/20161129_163448_newfeature_1</code></li></ul></li></ul><p><img src="./_image/2016-09-22-20-57-27.jpg" alt=""></p><ul><li>master:master永远是线上代码,最稳定的分支,存放的是随时可供在生产环境中部署的代码,当开发活动告一段落,产生了一份新的可供部署的代码时,发布成功之后,代码才会由 aone2 提交到 master,master 分支上的代码会被更新。应用上 aone2 后禁掉所有人的 master的写权限</li><li>develop:保存当前最新开发成果的分支。通常这个分支上的代码也是可进行每日夜间发布的代码,只对开发负责人开放develop权限。</li><li>feature: 功能特性分支,每个功能特性一个 feature/ 分支,开发完成自测通过后合并入 develop 分支。可以从 master 或者develop 中拉出来。</li><li>hotfix: 紧急bug分支修复分支。修复上线后,可以直接合并入master。</li></ul><p><img src="./_image/2016-07-19 19-58-15.jpg?r=60" alt=""></p><p>Git-Develop 分支模式是基于 Git 代码库设计的一种需要严格控制发布质量和发布节奏的开发模式。develop 作为固定的持续集成和发布分支,并且分支上的代码必须经过 CodeReview 后才可以提交到 Develop 分支。它的基本流程如下:</p><ul><li>每一个需求/变更都单独从Master上创建一条Branch分支;</li><li>用户在这个Branch分支上进行Codeing活动;</li><li>代码达到发布准入条件后aone上提交Codereview,Codereview通过后代码自动合并到Develop分支;</li><li>待所有计划发布的变更分支代码都合并到Develop后,系统再 rebase master 代码到Develop 分支,然后自行构建,打包,部署等动作。</li><li>应用发布成功后Aone会基于Develop分支的发布版本打一个“当前线上版本Tag”基线;</li><li>应用发布成功后Aone会自动把Develop分支的发布版本合并回master;</li></ul><h2 id="Branch-命令"><a href="#Branch-命令" class="headerlink" title="Branch 命令"></a>Branch 命令</h2><ul><li>查看分支:<code>git branch</code> 、<code>git branch -v</code>、<code>git branch -vv</code> (查看当前分支 tracking 哪个远端分支)、<code>git branch --merged</code>、<code>git branch --no-merged</code></li><li>创建分支:<code>git branch branchname</code><ul><li>例: 基于 master 分支新建 dev 分支 : <code>git branch dev</code></li></ul></li><li><p>基于之前的某个 Commit 新开分支: <code>git branch branchname <sha1-of-commit></code></p><ul><li>例: 基于上线的的提交 a207a38d634cc10441636bc4359cd8a18c502dea 创建 hotfix 分支 : <code>git branch hotfix a207a38</code></li><li>例: 基于 remoteBranch、localBranch、commitId、tag 创建分支均可以 <code>git checkout -b newbranch localBranch/remoteBranch/commitId/tag</code></li><li>例: 创建一个空的分支 <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">git checkout --orphan gh-pages <span class="comment"># 创建一个orphan的分支,这个分支是独立的</span></span><br><span class="line"> Switched to a new branch \<span class="string">'gh-pages\'</span></span><br><span class="line"> git rm -rf . <span class="comment"># 删除原来代码树下的所有文件</span></span><br><span class="line"> rm \<span class="string">'.gitignore\'</span></span><br><span class="line"> <span class="comment">#注意这个时候你用git branch命令是看不见当前分支的名字的,除非你进行了第一次commit。添加新的文件,并且 commit 掉,就能看到分支了。</span></span><br><span class="line">`</span><br></pre></td></tr></table></figure></li></ul></li><li><p>切换分支: <code>git checkout branchname</code></p><ul><li>例: 由分支 master 切换到 dev 分支:<code>git checkout dev</code></li></ul></li><li>创建新分支并切换到下面:<code>git checkout -b branchname</code> 或者 <code>git branch branchname && git checkout branchname</code><ul><li>例:基于 master 分支新建 dev 分支,并切换到 dev 分支上: <code>git checkout -b dev</code> 或 <code>git branch dev && git checkout dev</code></li></ul></li><li>查看分支代码不同:<code>git diff branchname</code> 比较 branchname 分支与当前分支的差异点,若只看文件差异,不看差异内容:<code>git diff branchName --stat</code></li><li>合并分支:<code>git merge branchname</code> 将 branchname 分支代码合并到当前分支</li><li>删除分支:<code>git branch -d branchname</code> 强制删除未合并过的分支:<code>git branch -D branchname</code></li><li>重命名分支: <code>git branch -m dev development</code> 将分支 dev 重命名为 development</li><li>查看远程分支:<code>git branch -r</code> 或 <code>git branch -r -v</code></li><li>获取远程分支到本地:<code>git checkout -b local-branchname origin/remote-branchname</code></li><li>推送本地分支到远程:<code>git push origin remote-branchname</code> 或 <code>git push origin local-branchname:remote-branchname</code><ul><li>将本地 dev 代码推送到远程 dev 分支: <code>git push (-u) origin dev</code> 或 <code>git push origin dev:dev</code></li><li>(技巧)将本地 dev 分支代码推送到远程 master 分支: <code>git push origin dev:master</code></li></ul></li><li>删除远程分支:<code>git push origin :remote-branchname</code> 或 <code>git push origin --delete remote-branchname</code></li><li>手动跟踪分支,master分支追踪origin/next分支: <code>git branch --track master origin/next</code> 或者 <code>git branch --set-upstream-to=origin/master</code> 看 git 的版本是否支持。</li><li>TrackingBranch,可以通过 <code>git branch -vv</code> 来查看当前 track 的分支情况。新建立分支时会自动 track 相应远程分支,<code>git checkout -b sf origin/serverfix</code> (Branch sf set up to track remote branch serverfix from origin. Switched to a new branch ‘sf’). 也可以手动 track: <code>git branch -u origin/serverfix</code> (Branch serverfix set up to track remote branch serverfix from origin). 等同于命令 <code>git checkout --track origin/serverfix</code></li></ul><blockquote><p>“Checking out a local branch from a remote branch automatically creates what is called a “tracking branch” (or sometimes an “upstream branch”). Tracking branches are local branches that have a direct relationship to a remote branch. If you’re on a tracking branch and type git pull, Git automatically knows which server to fetch from and branch to merge into.<br>When you clone a repository, it generally automatically creates a master branch that tracks origin/master. However, you can set up other tracking branches if you wish – ones that track branches on other remotes, or don’t track the master branch. The simple case is the example you just saw, running git checkout -b [branch] [remotename]/[branch]. This is a common enough operation that git provides the –track shorthand:”</p></blockquote><h1 id="Tag"><a href="#Tag" class="headerlink" title="Tag"></a>Tag</h1><ul><li>查看 tag:<code>git tag</code></li><li>查找指定 tag,比如查找 V1.0.<em> :`git tag -l ‘V1.0.</em>‘` 会列出匹配到的,比如 V1.0.1,V1.0.1.1,V1.0.2 等</li><li>创建轻量级 tag(lightweight tags):<code>git tag tag-name</code> ,例如: <code>git tag v1.0</code></li><li>创建 tag(annotated tags):<code>git tag -a tag-name -m 'msg'</code> ,例如:<code>git tag -a v1.0.0 -m '1.0.0版本上线完毕打tag'</code><ul><li>annotated tags VS lightweight tags 可以通过命令真实查看下:<code>git show v1.0</code> / <code>git show v1.0.0</code></li><li>“A lightweight tag is very much like a branch that doesn’t change – it’s just a pointer to a specific commit.<br>Annotated tags, however, are stored as full objects in the Git database. They’re checksummed; contain the tagger name, e-mail, and date; have a tagging message; and can be signed and verified with GNU Privacy Guard (GPG). ”</li></ul></li><li>查看指定 tag 信息:<code>git show tag-name</code></li><li>基于历史某次提交(commit)创建 tag :<code>git tag -a tagname <sha1-of-commit></code><ul><li>例:基于上线时的提交 a207a38d634cc10441636bc4359cd8a18c502dea 创建tag:<code>git tag -a v1.0.0 a207a38</code></li></ul></li><li>删除 tag :<code>git tag -d tagname</code></li><li>拉取远程 tag 到本地:<code>git pull remotename --tags</code> 例如:<code>git pull origin --tags</code></li><li>推送 tag 到远程服务器:<code>git push remotename tagname</code> 例如:<code>git push origin v1.0.0</code></li><li>将本地所有 tag 推送到远程:<code>git push remotename --tags</code> 例如:<code>git push origin --tags</code></li><li>删除远程 tag :<code>git push origin :tagname</code> 或者 <code>git push origin --delete tagname</code> 或者 <code>git push origin :refs/tags/v0.9</code></li></ul><h1 id="Submodule"><a href="#Submodule" class="headerlink" title="Submodule"></a>Submodule</h1><p>添加子模块:$ git submodule add [url] [path]<br> 如:$ git submodule add git://github.com/soberh/ui-libs.git src/main/webapp/ui-libs<br>初始化子模块:$ git submodule init —-只在首次检出仓库时运行一次就行<br>更新子模块:$ git submodule update —-每次更新或切换分支后都需要运行一下<br>删除子模块:(分4步走哦)<br> 1) $ git rm –cached [path]<br> 2) 编辑“.gitmodules”文件,将子模块的相关配置节点删除掉<br> 3) 编辑“ .git/config”文件,将子模块的相关配置节点删除掉<br> 4) 手动删除子模块残留的目录</p><h1 id="Stash"><a href="#Stash" class="headerlink" title="Stash"></a>Stash</h1><p>经常有这样的事情发生,当你正在进行项目中某一部分的工作,里面的东西处于一个比较杂乱的状态,而你想转到其他分支上进行一些工作。问题是,你不想提交进行了一半的工作,否则以后你无法回到这个工作点。解决这个问题的办法就是 <code>git stash</code> 命令。<br><code>stash</code> 可以获取你工作目录的中间状态,也就是你修改过的被追踪的文件和暂存的变更,并将它保存到一个未完结变更的堆栈中,随时可以重新应用。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">usage: git stash list [<options>] 查看当前 stash 的列表</span><br><span class="line"> or: git stash show [<stash>] 查看某一个版本的详细内容</span><br><span class="line"> or: git stash drop [-q|--quiet] [<stash>] 删除 stash 中内容</span><br><span class="line"> or: git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>] 将 stash 中的代码应用到工作区中</span><br><span class="line"> or: git stash branch <branchname> [<stash>]</span><br><span class="line"> or: git stash [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]</span><br><span class="line"> [-u|--include-untracked] [-a|--all] [<message>]]</span><br><span class="line"> or: git stash clear 清空 stash 中所有内容</span><br></pre></td></tr></table></figure><h1 id="oh-my-zsh-常用命令"><a href="#oh-my-zsh-常用命令" class="headerlink" title="oh-my-zsh 常用命令"></a>oh-my-zsh 常用命令</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">alias g='git'</span><br><span class="line">alias ga='git add'</span><br><span class="line">alias gco='git checkout'</span><br><span class="line">alias gcb='git checkout -b'</span><br><span class="line">alias gcm='git checkout master'</span><br><span class="line">alias gcd='git checkout develop'</span><br><span class="line">alias gd='git diff'</span><br><span class="line">alias gf='git fetch'</span><br><span class="line">alias gfo='git fetch origin'</span><br><span class="line">alias gl='git pull'</span><br><span class="line">alias gp='git push'</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h1 id="Alias"><a href="#Alias" class="headerlink" title="Alias"></a>Alias</h1><p>下面的只是例子,想改成什么跟随自己的意愿即可。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git config --global alias.st status //status 缩写成 st</span><br><span class="line">git config --global alias.co checkout //checkout 缩写成 co</span><br><span class="line">git config --global alias.br branch //branch 缩写成 br</span><br><span class="line">git config --global alias.ci commit //commit 缩写成 ci</span><br><span class="line">git config --global alias.lg <span class="string">"log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&lt;%an&gt;%Creset' --abbrev-commit"</span></span><br></pre></td></tr></table></figure></p>
</summary>
<category term="Git" scheme="http://mantoudev.com/categories/Git/"/>
<category term="Git" scheme="http://mantoudev.com/tags/Git/"/>
</entry>
<entry>
<title>Git快速入门</title>
<link href="http://mantoudev.com/Git%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/"/>
<id>http://mantoudev.com/Git快速入门/</id>
<published>2016-11-01T04:00:00.000Z</published>
<updated>2018-11-27T08:49:01.050Z</updated>
<content type="html"><![CDATA[<h1 id="Git-快速入门"><a href="#Git-快速入门" class="headerlink" title="Git 快速入门"></a>Git 快速入门</h1><h2 id="0-Git简介"><a href="#0-Git简介" class="headerlink" title="0. Git简介"></a>0. Git简介</h2><p>git是一个分布式版本控制软件,最初由林纳斯·托瓦兹(Linus Torvalds)创作,于2005年以GPL发布。最初目的是为更好地管理Linux内核开发而设计。Git可以在任何时间点,把文档的状态作为更新记录保存起来。因此可以把编辑过的文档复原到以前的状态,也可以显示编辑前后的内容差异。而且,编辑旧文件后,试图覆盖较新的文件的时候(即上传文件到服务器时),系统会发出警告,因此可以避免在无意中覆盖了他人的编辑内容。<br><a id="more"></a></p><p>更多内容请查看<a href="https://zh.wikipedia.org/wiki/Git" target="_blank" rel="noopener">Git维基百科。</a></p><h2 id="1-Git-Vs-SVN"><a href="#1-Git-Vs-SVN" class="headerlink" title="1. Git Vs SVN"></a>1. Git Vs SVN</h2><p>分布式 vs 集中管理 (多份版本库 vs 一份版本库,设想下版本服务器挂了?)<br>无需网络,随时随地进行版本控制,在没有网络的情况下你想回退到某个版本svn基本没戏;<br>分支的新建、合并非常方便、快速,没有任何成本,基本不耗时,svn的版本基本上等同于又复制了一份代码。</p><p><a href="https://stackoverflow.com/questions/871/why-is-git-better-than-subversion" target="_blank" rel="noopener">stackoverflow 上关于svn和git的区别的讨论</a>,说的很详细,请参考 Why is Git better than Subversion?</p><p>Github上通过版本库结构、历史、子项目(submudle)的不同来对比两者,请参考Github的 <a href="https://help.github.com/articles/what-are-the-differences-between-subversion-and-git/" target="_blank" rel="noopener">What are the differences between SVN and Git?</a></p><h2 id="2-安装"><a href="#2-安装" class="headerlink" title="2.安装"></a>2.安装</h2><p>通过<a href="https://git-scm.com/downloads" target="_blank" rel="noopener">官网</a>安装。</p><p>下面推荐各个OS的GUI( 图形用户界面)Git工具,但还是强烈推荐使用命令行操作Git。</p><ul><li><p><strong>Windows</strong><br>乌龟Tortoisegit<br><a href="https://tortoisegit.org/" target="_blank" rel="noopener">https://tortoisegit.org/</a></p></li><li><p><strong>Mac</strong><br>免费的SourceTree客户端。<br><a href="http://www.sourcetreeapp.com/" target="_blank" rel="noopener">http://www.sourcetreeapp.com/</a></p></li><li><p><strong>Linux</strong><br>不推荐客户端,可以使用发行版包含的基础软件包管理工具来安装。 如果以 Fedora 上为例,你可以使用 yum:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sudo yum install git</span><br></pre></td></tr></table></figure></li></ul><p>如果你在基于 Debian 的发行版上,请尝试用 apt-get:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sudo apt-get install git</span><br></pre></td></tr></table></figure></p><h2 id="3-配置"><a href="#3-配置" class="headerlink" title="3. 配置"></a>3. 配置</h2><p>Git 自带一个 git config 的工具来帮助设置控制 Git 外观和行为的配置变量。 这些变量存储在三个不同的位置:</p><ol><li><p><code>/etc/gitconfig</code> 文件: 包含系统上每一个用户及他们仓库的通用配置。 如果使用带有 <code>--system</code> 选项的 <code>git config</code> 时,它会从此文件读写配置变量。</p></li><li><p><code>~/.gitconfig</code> 或 <code>~/.config/git/config</code> 文件:只针对当前用户。 可以传递 <code>--global</code> 选项让 Git 读写此文件。</p></li><li><p>当前使用仓库的 Git 目录中的 config 文件(就是 <code>.git/config</code>):针对该仓库。</p></li></ol><p>每一个级别覆盖上一级别的配置,所以 .git/config 的配置变量会覆盖 /etc/gitconfig 中的配置变量。</p><p>在 Windows 系统中,Git 会查找 $HOME 目录下(一般情况下是 <code>C:\Users\$USER</code>)的 .gitconfig 文件。 Git 同样也会寻找 <code>/etc/gitconfig</code> 文件,但只限于 MSys 的根目录下,即安装 Git 时所选的目标位置。</p><h3 id="3-1-用户信息配置"><a href="#3-1-用户信息配置" class="headerlink" title="3.1 用户信息配置"></a>3.1 用户信息配置</h3><p>每一个 Git 的提交都会使用这些信息,并且它会写入到你的每一次提交中,不可更改:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ git config --global user.name "mantoudev"</span><br><span class="line">$ git config --global user.email [email protected]</span><br></pre></td></tr></table></figure><p>如果使用了 –global 选项,那么该命令只需要运行一次,因为之后无论你在该系统上做任何事情, Git 都会使用那些信息。 当你想针对特定项目使用不同的用户名称与邮件地址时,可以在那个项目目录下运行没有 –global 选项的命令来配置。</p><p>很多 GUI 工具都会在第一次运行时帮助你配置这些信息。</p><h3 id="3-2-检查配置信息"><a href="#3-2-检查配置信息" class="headerlink" title="3.2 检查配置信息"></a>3.2 检查配置信息</h3><p>如果想要检查你的配置,可以使用 <code>git config --list</code> 命令来列出所有 Git 当时能找到的配置。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">$ git config --list</span><br><span class="line">user.name=mantoudev</span><br><span class="line">[email protected]</span><br><span class="line">color.status=auto</span><br><span class="line">color.branch=auto</span><br><span class="line">color.interactive=auto</span><br><span class="line">color.diff=auto</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>你可能会看到重复的变量名,因为 Git 会从不同的文件中读取同一个配置(例如:<code>/etc/gitconfig 与 ~/.gitconfig</code>)。 这种情况下,Git 会使用它找到的每一个变量的最后一个配置。</p><p>你可以通过输入 <code>git config <key>:</code> 来检查 Git 的某一项配置</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ git config user.name</span><br><span class="line">mantoudev</span><br></pre></td></tr></table></figure><h2 id="4-基本常用命令"><a href="#4-基本常用命令" class="headerlink" title="4. 基本常用命令"></a>4. 基本常用命令</h2><h5 id="(1)-添加文件到暂存区(staged)"><a href="#(1)-添加文件到暂存区(staged)" class="headerlink" title="(1) 添加文件到暂存区(staged)"></a>(1) 添加文件到暂存区(staged)</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ git add filename</span><br><span class="line"> #或</span><br><span class="line">$ git stage filename</span><br></pre></td></tr></table></figure><h5 id="(2)-将所有修改文件添加到暂存区(staged)"><a href="#(2)-将所有修改文件添加到暂存区(staged)" class="headerlink" title="(2) 将所有修改文件添加到暂存区(staged)"></a>(2) 将所有修改文件添加到暂存区(staged)</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ git add --all</span><br><span class="line">#或</span><br><span class="line">$ git add -A</span><br></pre></td></tr></table></figure><h5 id="(3)-提交修改到暂存区(staged)"><a href="#(3)-提交修改到暂存区(staged)" class="headerlink" title="(3) 提交修改到暂存区(staged)"></a>(3) 提交修改到暂存区(staged)</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ git commit -m 'commit message'</span><br><span class="line">$ git commit -a -m 'commit message'</span><br></pre></td></tr></table></figure><p>注意理解 -a 参数的意义</p><h5 id="(4)-从Git仓库中删除文件:"><a href="#(4)-从Git仓库中删除文件:" class="headerlink" title="(4) 从Git仓库中删除文件:"></a>(4) 从Git仓库中删除文件:</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git rm filename</span><br></pre></td></tr></table></figure><h5 id="(5)-从Git仓库中删除文件,但本地文件保留:"><a href="#(5)-从Git仓库中删除文件,但本地文件保留:" class="headerlink" title="(5) 从Git仓库中删除文件,但本地文件保留:"></a>(5) 从Git仓库中删除文件,但本地文件保留:</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git rm --cached filename</span><br></pre></td></tr></table></figure><h5 id="(6)-重命名某个文件:"><a href="#(6)-重命名某个文件:" class="headerlink" title="(6) 重命名某个文件:"></a>(6) 重命名某个文件:</h5> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ git mv filename newfilename</span><br><span class="line">#或者直接修改完毕文件名 ,进行</span><br><span class="line">$ git add -A && git commit -m 'commit message'</span><br></pre></td></tr></table></figure><p>Git会自动识别是重命名了文件</p><h5 id="(7)-获取远程最新代码到本地:"><a href="#(7)-获取远程最新代码到本地:" class="headerlink" title="(7) 获取远程最新代码到本地:"></a>(7) 获取远程最新代码到本地:</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git pull (origin branchname)</span><br></pre></td></tr></table></figure><p>可以指定分支名,也可以忽略。pull 命令自动 fetch 远程代码并且 merge,如果有冲突,会显示在状态栏,需要手动处理。更推荐使用:<code>git fetch</code> 之后 <code>git merge --no-ff origin branchname</code> 拉取最新的代码到本地仓库,并手动 merge 。</p><h2 id="5-Git-commit-messge规范"><a href="#5-Git-commit-messge规范" class="headerlink" title="5. Git commit messge规范"></a>5. Git commit messge规范</h2><p>查看Commit message</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git log <last tag> HEAD --pretty=format:%s</span><br></pre></td></tr></table></figure><h4 id="5-1-Commit-Message格式"><a href="#5-1-Commit-Message格式" class="headerlink" title="5.1 Commit Message格式"></a>5.1 Commit Message格式</h4><p>每次提交,Commit message 都包括三个部分:Header,Body 和 Footer。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><type>(<scope>): <subject></span><br><span class="line">// 空一行</span><br><span class="line"><body></span><br><span class="line">// 空一行</span><br><span class="line"><footer></span><br></pre></td></tr></table></figure><p>其中,Header 是必需的,Body 和 Footer 可以省略。<br>不管是哪一个部分,任何一行都不得超过72个字符(或100个字符)。</p><h4 id="5-2-Header"><a href="#5-2-Header" class="headerlink" title="5.2 Header"></a>5.2 Header</h4><p>Header部分只有一行,包括三个字段:type(必需)、scope(可选)和subject(必需)。</p><h5 id="(1)type"><a href="#(1)type" class="headerlink" title="(1)type"></a>(1)type</h5><p><code>type</code>用于说明 commit 的类别,只允许使用下面7个标识。</p><ul><li>feat:新功能(feature)</li><li>fix:修补bug</li><li>docs:文档(documentation)</li><li>style: 格式(不影响代码运行的变动)</li><li>refactor:重构(即不是新增功能,也不是修改bug的代码变动)</li><li>test:增加测试</li><li>chore:构建过程或辅助工具的变动</li><li>revert: 撤销以前的 commit,后面跟着被撤销 Commit 的 Header。</li></ul><h5 id="(2)scope"><a href="#(2)scope" class="headerlink" title="(2)scope"></a>(2)scope</h5><p><code>scope</code>用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。</p><h5 id="(3)subject"><a href="#(3)subject" class="headerlink" title="(3)subject"></a>(3)subject</h5><p><code>subject</code>是 commit 目的的简短描述,不超过50个字符。</p><ul><li>以动词开头,使用第一人称现在时,比如change,而不是changed或changes</li><li>第一个字母小写</li><li>结尾不加句号(.)</li></ul><h4 id="5-3-Body"><a href="#5-3-Body" class="headerlink" title="5.3 Body"></a>5.3 Body</h4><p>Body 部分是对本次 commit 的详细描述,可以分成多行。下面是一个范例。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">此次修改主要对****功能模块进行重构,包含以下部分:</span><br><span class="line"></span><br><span class="line">1. AAAAAAA....</span><br><span class="line">2. BBBBBBB....</span><br><span class="line">3. CCCCCCC....</span><br></pre></td></tr></table></figure><p>body中还可以与一些Bug管理工具进行关联,在Header之后换行添加</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Bug: <Bug编号></span><br></pre></td></tr></table></figure><h4 id="5-4-Footer"><a href="#5-4-Footer" class="headerlink" title="5.4 Footer"></a>5.4 Footer</h4><h5 id="(1)不兼容变动"><a href="#(1)不兼容变动" class="headerlink" title="(1)不兼容变动"></a>(1)不兼容变动</h5><p>如果当前代码与上一个版本不兼容,则 Footer 部分以<code>BREAKING CHANGE</code>开头,后面是对变动的描述、以及变动理由和迁移方法。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">BREAKING CHANGE: isolate scope bindings definition has changed.</span><br><span class="line"></span><br><span class="line"> To migrate the code follow the example below:</span><br><span class="line"></span><br><span class="line"> Before:</span><br><span class="line"></span><br><span class="line"> scope: {</span><br><span class="line"> myAttr: 'attribute',</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> After:</span><br><span class="line"></span><br><span class="line"> scope: {</span><br><span class="line"> myAttr: '@',</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> The removed `inject` wasn't generaly useful for directives</span><br></pre></td></tr></table></figure><h5 id="2-关闭-Issue"><a href="#2-关闭-Issue" class="headerlink" title="(2) 关闭 Issue"></a>(2) 关闭 Issue</h5><p>如果当前 commit 针对某个issue,那么可以在 Footer 部分关闭这个 issue 。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Closes #234</span><br></pre></td></tr></table></figure><h5 id="3-签名"><a href="#3-签名" class="headerlink" title="(3) 签名"></a>(3) 签名</h5><p>如果commit使用签名的话,footer中会包含签名信息</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Signed-off-by: mantoudev <[email protected]></span><br></pre></td></tr></table></figure><h5 id="4-其他"><a href="#4-其他" class="headerlink" title="(4) 其他"></a>(4) 其他</h5><p>使用gerrit(代码审查工具,<a href="https://zh.wikipedia.org/wiki/Gerrit" target="_blank" rel="noopener">gerrit维基百科</a>),在footer中会生成一个ChanggeId,一个ChangeId标识一次内容变化,可以包含多个commit,即多个commit如果changeid一致的话,可以认为是一个change。</p><h2 id="6-乱码处理"><a href="#6-乱码处理" class="headerlink" title="6. 乱码处理"></a>6. 乱码处理</h2><p>Linux 、MacOS默认编码为utf-8,windows默认编码为GBK。提交时编码不统一,或者展示时编码不统一,会出现乱码的情况。</p><h4 id="6-1-git-status时中文文件名乱码"><a href="#6-1-git-status时中文文件名乱码" class="headerlink" title="6.1 git status时中文文件名乱码"></a>6.1 <code>git status</code>时中文文件名乱码</h4><p>现象:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\344\275\240\345\245\275</span><br></pre></td></tr></table></figure><p>执行以下命令即可:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git config --global core.quotepath false</span><br></pre></td></tr></table></figure><p>quotepath解释:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">The commands that output paths (e.g. ls-files, diff), when not given the -z option,will quote "unusual" characters in the pathname by enclosing the pathname in a double-quote pair and with backslashes the same way strings in C source code are quoted. If this variable is set to false, the bytes higher than 0x80 are not quoted but output as verbatim. Note that double quote, backslash and control characters are always quoted without -z regardless of the setting of this variable.</span><br></pre></td></tr></table></figure><h4 id="6-2-git-log-查看提交中含中文乱码"><a href="#6-2-git-log-查看提交中含中文乱码" class="headerlink" title="6.2 git log 查看提交中含中文乱码"></a>6.2 <code>git log</code> 查看提交中含中文乱码</h4><p>现象:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><E4><BF><AE><E6></span><br></pre></td></tr></table></figure><ul><li>修改git全局配置设置提交和查看日志编码都是utf-8</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config --global i18n.commitencoding utf-8</span><br><span class="line">git config --global i18n.logoutputencoding utf-8</span><br></pre></td></tr></table></figure><ul><li>修改git目录下etc\profile文件,设置less的字符集为utf-8</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">export LESSCHARSET=utf-8</span><br></pre></td></tr></table></figure><ul><li>(Windows)修改cmder目录vendor\init.bat文件,添加以下代码,设定cmder编码为utf-8</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@chcp 65001 > nul</span><br></pre></td></tr></table></figure><p>chcp 65001的解释:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Why is there no option to choose codepage 65001 (UTF-8) as a default codepage in console window</span><br></pre></td></tr></table></figure><h4 id="6-3-gitk查看中文乱码"><a href="#6-3-gitk查看中文乱码" class="headerlink" title="6.3 gitk查看中文乱码"></a>6.3 gitk查看中文乱码</h4><p>解决办法:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git config --global gui.encoding utf-8</span><br></pre></td></tr></table></figure><h2 id="7-参考资料"><a href="#7-参考资料" class="headerlink" title="7. 参考资料"></a>7. 参考资料</h2><ol><li><a href="https://git-scm.com/book/zh/v2" target="_blank" rel="noopener">Git-scm官方文档</a> </li><li><a href="https://backlog.com/git-tutorial/cn/" target="_blank" rel="noopener">猴子都能懂的Git系列</a></li><li><a href="https://github.com/xirong/my-git" target="_blank" rel="noopener">Git学习资料汇总</a></li></ol>]]></content>
<summary type="html">
<h1 id="Git-快速入门"><a href="#Git-快速入门" class="headerlink" title="Git 快速入门"></a>Git 快速入门</h1><h2 id="0-Git简介"><a href="#0-Git简介" class="headerlink" title="0. Git简介"></a>0. Git简介</h2><p>git是一个分布式版本控制软件,最初由林纳斯·托瓦兹(Linus Torvalds)创作,于2005年以GPL发布。最初目的是为更好地管理Linux内核开发而设计。Git可以在任何时间点,把文档的状态作为更新记录保存起来。因此可以把编辑过的文档复原到以前的状态,也可以显示编辑前后的内容差异。而且,编辑旧文件后,试图覆盖较新的文件的时候(即上传文件到服务器时),系统会发出警告,因此可以避免在无意中覆盖了他人的编辑内容。<br>
</summary>
<category term="Git" scheme="http://mantoudev.com/categories/Git/"/>
<category term="Git" scheme="http://mantoudev.com/tags/Git/"/>
</entry>
</feed>