Fork me on GitHub

周末推荐 Vol. 1

推荐些书籍和影视作品 🙃,充实周末

1. 书籍

1.1《万万没想到:用理工科思维理解世界》

本书精选了万维钢老师的文章和书评,以“用理工科思维理解世界”为导向。作者常用有趣的实验、数据来解读感性的事物,其理工科思维涉及行为经济学、认知心理学、社会学、统计学、物理等许多学科,以前沿的科学视角解读生活,为人们提供了认知的新方法。读完本书相当于精读了十几本经过筛选 、再创作及通俗化处理的巨著,不仅有趣还十分有营养。

豆瓣评分8.2

1.2《罗素思想小品》

本书由西方思想研究者、权威译者张广勇先生编译,汇集了罗素富有思想性和可读性的作品,涉及哲学、政治、社会、文化、教育、人生、伦理等各个方面。他的机智和幽默,博学与深思,让读者不仅可以获得阅读的喜悦,更能收获生活的智慧。

豆瓣评分7.9

2. 动漫

2.1《我的三体之章北海传》

《我的三体》是一部粉丝自制的动画番剧,旨在以MC风格将《三体》的故事做成动画。《我的三体》改编自刘慈欣的科幻小说《三体》,且对原著部分剧情进行了删改,除正片外,制作团队还制作了一系列符合原著描写的角色歌。

豆瓣评分9.7分,墙裂推荐,很喜欢,这是第三季,第二季《我的三体之罗辑传》也推荐看

2.2《异度侵入ID:INVADED》

本片讲述利用能检测出人们杀意的装置以及利用思想粒子做出的“井”,来探知事件真相的科幻故事

豆瓣评分9.4,推理番

3. 电视剧

3.1《王国第二季》

豆瓣评分8.4,续作,第一季就很喜欢

4. 综艺节目

4.1《周游记》

周杰伦综艺节目。周杰伦的朋友全情参与,方文山、刘德华、五月天、萧敬腾、林俊杰、谢霆锋、陈建州等将和周杰伦一起周游世界,每个城市一首周杰伦歌曲,全程无脚本拍摄,周杰伦全程参与,魔术技能大秀,去巴黎解码《告白气球》,去新加坡看林俊杰《听妈妈的话》,和谢霆锋富士山下看《最长的电影》。

使用 electron 创建微信读书Mac客户端

2019年11月,微信读书上线了网页版,使用微信读书变得更加便捷了,但使用网页版需要在浏览器打开,会多一个打开浏览器的步骤。

而且将微信读书跟其他网页混在一起使用,感觉自己丢失了一种仪式感和踏实感,因此我用 electron 将微信读书网页版封装为了一个桌面应用程序。

下载地址:https://github.com/gaohanghang/WeChatRead/releases

首先看下使用效果

1. 效果

1. 安装

下载地址:https://github.com/gaohanghang/WeChatRead/releases

2. 使用

2. 微信读书是什么

微信读书是微信推出的一款基于微信的阅读应用,之前,大家只能安装APP后才能访问,2019年11月微信悄悄上线了微信读书网页版,这对于喜欢在PC上阅读的小伙伴来讲是个好消息。从目前的页面来看,用户可以扫码登录,账户与手机APP同步,也可以查看书架,访问微信读书海量资源,体验不错。

官方公布数据显示,目前微信读书注册用户数2.1亿,日活跃用户超过500万,其中19-35岁年轻用户占比超过60%,本科及以上学历用户占比高达80%,北上广深及其他省会城市/直辖市用户占比超过80%。

微信方面表示,微信读书的深度阅读定位和文化知识调性聚集了大量年轻化、高学历的优质用户,使微信读书尤其符合高端定位品牌对于优质曝光环境和高端人群触达的需求。

—— from 微信读书网页版悄然上线:体验优秀

img

3. 最后

可能有人会说直接浏览器打开不就行了,何必多次一举 😂

我想说用浏览器打开当然也可以,每个人都有各自的使用习惯,我是比较喜欢用 PC 客户端看书,多一种选择总归是好的

4. 参考文章

打造你的第一个 Electron 应用

如何用 nativefier 将网页打包成客户端 App

微信读书网页版悄然上线:体验优秀

为什么我推荐你用语雀记笔记 置顶

1. 什么语雀

「语雀」是一个「专业的云端知识库」,孵化自 蚂蚁金服 ,是 体验科技 理念下的一款创新产品,已是 10 万阿里员工进行文档编写、知识沉淀的标配。注册后即可免费使用。

以下为我的语雀页面

我的语雀链接:https://www.yuque.com/gaohanghang

2. 我为什么选择语雀

其实我对自己理想中的笔记软件只有以下几点要求

  • 能用 Markdown
  • 支持无限层级
  • 能在网上使用并被别人看到

2.1 为什么需要支持 Markdown?

Markdown是一种轻量级标记语言,创始人为约翰·格鲁伯(John Gruber),允许人们使用易读易写的纯文本格式编写文档,然后将文本格式转换成有效的XHTML(或者HTML)文档。

使用 Markdown 进行写作会非常方便,首先是学习成本很低,记住几个常用的用法就可以写出干净排版的文章了。自从我在大学学会用 Markdown 之后,我就再也不想用 Word 写文档了。我觉得 Markdown 应该会成为主流的文档书写语言

其次是可移植性高,现在基本所有常见的技术博客平台都支持通过 Markdown 进行写作了,比如 CSDN、博客园、简书、掘金、segmentfault 思否、开源中国这些博客平台。文章在一个平台写完之后,可以很方便的复制到其他平台进行发布。

当然也可以找个一文多发的平台,直接一键将文章发布到所有博客平台,如 OpenWrite 和 ArtiPub,我比较喜欢使用 ArtiPub 。

2.2 为什么需要支持无限层级?

因为知识的结构肯定是树形的,只有无限层级的目录才能方便的构建你的知识体系。无限层级的目录能够很方便的存储元知识。元知识,即不可分割的最小知识点。

而普通的笔记软件,目录层级只有一两层,知识的之间的关系不够直观,不能显著的构建一个立体的知识结构,得到的只是线和平面的结构。微软的 OneNote 是支持无限层级的,我之前使用的笔记软件也是这个,但可惜官方一直不支持 Markdown ,用的一直有些痛苦。

像下面这样,在语雀中我可以不断的添加目录层级

2.3 为什么要能在网上使用并被别人看到呢?

能在网上使用首先是因为可以防止文档丢失,如果你只是在自己电脑上记笔记,就会有可能发生不可预测的意外从而丢失自己写过的东西。

阅读更多...

Java 8 Stream.reduce() 使用示例

原文地址:https://mkyong.com/java8/java-8-stream-reduce-examples/

作者:mkyong

翻译:高行行

在 Java 8 中,Stream.reduce()合并流的元素并产生单个值。

使用 for 循环的简单求和运算。

1
2
3
4
5
6
7
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sum = 0;
for (int i : numbers) {
sum += i;
}

System.out.println("sum : " + sum); // 55

相当于 Stream.reduce()

1
2
3
4
5
6
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// 1st argument, init value = 0
int sum = Arrays.stream(numbers).reduce(0, (a, b) -> a + b);

System.out.println("sum : " + sum); // 55

或方法引用 Integer::sum

1
int sum = Arrays.stream(numbers).reduce(0, Integer::sum); // 55

Integer.java

1
2
3
4
5
6
7
8
9
10
11
12
/**
* Adds two integers together as per the + operator.
*
* @param a the first operand
* @param b the second operand
* @return the sum of {@code a} and {@code b}
* @see java.util.function.BinaryOperator
* @since 1.8
*/
public static int sum(int a, int b) {
return a + b;
}

1. 方法签名

1.1 查看Stream.reduce()方法签名:

Stream.java

1
T reduce(T identity, BinaryOperator<T> accumulator);

IntStream.java

1
int reduce(int identity, IntBinaryOperator op);

LongStream.java

1
long reduce(int identity, LongBinaryOperator op);
  • identity = 默认值或初始值。
  • BinaryOperator = 函数式接口,取两个值并产生一个新值。(注: java Function 函数中的 BinaryOperator 接口用于执行 lambda 表达式并返回一个 T 类型的返回值)

1.2 如果缺少identity参数,则没有默认值或初始值,并且它返回 optional。

Stream.java

1
Optional<T> reduce(BinaryOperator<T> accumulator);

2. 更多例子

2.1 数学运算。

1
2
3
4
5
6
7
8
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

int sum = Arrays.stream(numbers).reduce(0, (a, b) -> a + b); // 55
int sum2 = Arrays.stream(numbers).reduce(0, Integer::sum); // 55

int sum3 = Arrays.stream(numbers).reduce(0, (a, b) -> a - b); // -55
int sum4 = Arrays.stream(numbers).reduce(0, (a, b) -> a * b); // 0, initial is 0, 0 * whatever = 0
int sum5 = Arrays.stream(numbers).reduce(0, (a, b) -> a / b); // 0

2.2 最大和最小

1
2
3
4
5
6
7
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

int max = Arrays.stream(numbers).reduce(0, (a, b) -> a > b ? a : b); // 10
int max1 = Arrays.stream(numbers).reduce(0, Integer::max); // 10

int min = Arrays.stream(numbers).reduce(0, (a, b) -> a < b ? a : b); // 0
int min1 = Arrays.stream(numbers).reduce(0, Integer::min); // 0

2.3 连接字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
String[] strings = {"a", "b", "c", "d", "e"};

// |a|b|c|d|e , the initial | join is not what we want
String reduce = Arrays.stream(strings).reduce("", (a, b) -> a + "|" + b);

// a|b|c|d|e, filter the initial "" empty string
String reduce2 = Arrays.stream(strings).reduce("", (a, b) -> {
if (!"".equals(a)) {
return a + "|" + b;
} else {
return b;
}
});

// a|b|c|d|e , better uses the Java 8 String.join :) (最好使用 Java 8 的 String.join)
String join = String.join("|", strings);

3. Map & Reduce

一个简单的 map 和 reduce 示例,用于从发票 List 中求 BigDecimal 的和。

JavaReduce.java

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
package com.mkyong;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;

public class JavaReduce {

public static void main(String[] args) {

// 发票集合
List<Invoice> invoices = Arrays.asList(
new Invoice("A01", BigDecimal.valueOf(9.99), BigDecimal.valueOf(1)),
new Invoice("A02", BigDecimal.valueOf(19.99), BigDecimal.valueOf(1.5)),
new Invoice("A03", BigDecimal.valueOf(4.99), BigDecimal.valueOf(2))
);

BigDecimal sum = invoices.stream()
.map(x -> x.getQty().multiply(x.getPrice())) // map,对集合中的元素进行操作
.reduce(BigDecimal.ZERO, BigDecimal::add); // reduce,将上一步得到的结果进行合并得到最终的结果

System.out.println(sum); // 49.955
System.out.println(sum.setScale(2, RoundingMode.HALF_UP)); // 49.96 使用setScale方法进行四舍五入

}

}

class Invoice {

// 发票号码
String invoiceNo;
// 价格
BigDecimal price;
// 数量
BigDecimal qty;

// getters, stters n constructor
}

输出

1
2
49.955
49.96

你必须知道的23个最有用的Elasticseaerch检索技巧

前言

本文主要介绍 Elasticsearch 23种最有用的检索技巧,提供了详尽的源码举例,并配有相应的Java API实现,是不可多得的 Elasticsearch 学习&实战资料

数据准备

为了讲解不同类型 ES 检索,我们将要对包含以下类型的文档集合进行检索:

1
2
3
4
5
6
7
title               标题
authors 作者
summary 摘要
publish_date 发布日期
num_reviews 评论数
publisher 出版社

首先,我们借助 bulk API 批量创建新的索引并提交数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 设置索引 settings
PUT /bookdb_index
{ "settings": { "number_of_shards": 1 }}

# bulk 提交数据
POST /bookdb_index/book/_bulk
{"index":{"_id":1}}
{"title":"Elasticsearch: The Definitive Guide","authors":["clinton gormley","zachary tong"],"summary":"A distibuted real-time search and analytics engine","publish_date":"2015-02-07","num_reviews":20,"publisher":"oreilly"}
{"index":{"_id":2}}
{"title":"Taming Text: How to Find, Organize, and Manipulate It","authors":["grant ingersoll","thomas morton","drew farris"],"summary":"organize text using approaches such as full-text search, proper name recognition, clustering, tagging, information extraction, and summarization","publish_date":"2013-01-24","num_reviews":12,"publisher":"manning"}
{"index":{"_id":3}}
{"title":"Elasticsearch in Action","authors":["radu gheorge","matthew lee hinman","roy russo"],"summary":"build scalable search applications using Elasticsearch without having to do complex low-level programming or understand advanced data science algorithms","publish_date":"2015-12-03","num_reviews":18,"publisher":"manning"}
{"index":{"_id":4}}
{"title":"Solr in Action","authors":["trey grainger","timothy potter"],"summary":"Comprehensive guide to implementing a scalable search engine using Apache Solr","publish_date":"2014-04-05","num_reviews":23,"publisher":"manning"}

注意:本文实验使用的ES版本是 ES 6.3.0

1、基本匹配检索( Basic Match Query)

1.1 全文检索

有两种方式可以执行全文检索:

1)使用包含参数的检索API,参数作为URL的一部分

举例:以下对 “guide” 执行全文检索

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
GET bookdb_index/book/_search?q=guide

[Results]
"hits": {
"total": 2,
"max_score": 1.3278645,
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "4",
"_score": 1.3278645,
"_source": {
"title": "Solr in Action",
"authors": [
"trey grainger",
"timothy potter"
],
"summary": "Comprehensive guide to implementing a scalable search engine using Apache Solr",
"publish_date": "2014-04-05",
"num_reviews": 23,
"publisher": "manning"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "1",
"_score": 1.2871116,
"_source": {
"title": "Elasticsearch: The Definitive Guide",
"authors": [
"clinton gormley",
"zachary tong"
],
"summary": "A distibuted real-time search and analytics engine",
"publish_date": "2015-02-07",
"num_reviews": 20,
"publisher": "oreilly"
}
}
]
}

2)使用完整的ES DSL,其中Json body作为请求体 其执行结果如方式 1)结果一致.

1
2
3
4
5
6
7
8
9
10
GET bookdb_index/book/_search
{
"query": {
"multi_match": {
"query": "guide",
"fields" : ["_all"]
}
}
}

解读: 使用multi_match关键字代替match关键字,作为对多个字段运行相同查询的方便的简写方式。 fields属性指定要查询的字段,在这种情况下,我们要对文档中的所有字段进行查询

注意:ES 6.x 默认不启用 _all 字段, 不指定 fields 默认搜索为所有字段

1.2 指定特定字段检索

这两个API也允许您指定要搜索的字段。
例如,要在标题字段(title)中搜索带有 “in action” 字样的图书

1)URL检索方式

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
GET bookdb_index/book/_search?q=title:in action

[Results]
"hits": {
"total": 2,
"max_score": 1.6323128,
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "3",
"_score": 1.6323128,
"_source": {
"title": "Elasticsearch in Action",
"authors": [
"radu gheorge",
"matthew lee hinman",
"roy russo"
],
"summary": "build scalable search applications using Elasticsearch without having to do complex low-level programming or understand advanced data science algorithms",
"publish_date": "2015-12-03",
"num_reviews": 18,
"publisher": "manning"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "4",
"_score": 1.6323128,
"_source": {
"title": "Solr in Action",
"authors": [
"trey grainger",
"timothy potter"
],
"summary": "Comprehensive guide to implementing a scalable search engine using Apache Solr",
"publish_date": "2014-04-05",
"num_reviews": 23,
"publisher": "manning"
}
}
]
}

2)DSL检索方式 然而,full body的DSL为您提供了创建更复杂查询的更多灵活性(我们将在后面看到)以及指定您希望的返回结果。在下面的示例中,我们指定要返回的结果数、偏移量(对分页有用)、我们要返回的文档字段以及属性的高亮显示。

结果数的表示方式:size
偏移值的表示方式:from
指定返回字段 的表示方式 :_source
高亮显示 的表示方式 :highliaght

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
GET bookdb_index/book/_search
{
"query": {
"match": {
"title": "in action"
}
},
"size": 2,
"from": 0,
"_source": ["title", "summary", "publish_date"],
"highlight": {
"fields": {
"title": {}
}
}
}

[Results]
"hits": {
"total": 2,
"max_score": 1.6323128,
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "3",
"_score": 1.6323128,
"_source": {
"summary": "build scalable search applications using Elasticsearch without having to do complex low-level programming or understand advanced data science algorithms",
"title": "Elasticsearch in Action",
"publish_date": "2015-12-03"
},
"highlight": {
"title": [
"Elasticsearch <em>in</em> <em>Action</em>"
]
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "4",
"_score": 1.6323128,
"_source": {
"summary": "Comprehensive guide to implementing a scalable search engine using Apache Solr",
"title": "Solr in Action",
"publish_date": "2014-04-05"
},
"highlight": {
"title": [
"Solr <em>in</em> <em>Action</em>"
]
}
}
]
}

注意:

  1. 对于 multi-word 检索,匹配查询允许您指定是否使用 and 运算符, 而不是使用默认 or 运算符 —> “operator” : “and”
  2. 您还可以指定 minimum_should_match 选项来调整返回结果的相关性,详细信息可以在Elasticsearch指南中查询Elasticsearch guide获取。

如我们已经看到的,要在搜索中查询多个文档字段(例如在标题和摘要中搜索相同的查询字符串),请使用multi_match查询

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
GET bookdb_index/book/_search
{
"query": {
"multi_match": {
"query": "guide",
"fields": ["title", "summary"]
}
}
}

[Results]
"hits": {
"total": 3,
"max_score": 2.0281231,
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "1",
"_score": 2.0281231,
"_source": {
"title": "Elasticsearch: The Definitive Guide",
"authors": [
"clinton gormley",
"zachary tong"
],
"summary": "A distibuted real-time search and analytics engine",
"publish_date": "2015-02-07",
"num_reviews": 20,
"publisher": "oreilly"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "4",
"_score": 1.3278645,
"_source": {
"title": "Solr in Action",
"authors": [
"trey grainger",
"timothy potter"
],
"summary": "Comprehensive guide to implementing a scalable search engine using Apache Solr",
"publish_date": "2014-04-05",
"num_reviews": 23,
"publisher": "manning"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "3",
"_score": 1.0333893,
"_source": {
"title": "Elasticsearch in Action",
"authors": [
"radu gheorge",
"matthew lee hinman",
"roy russo"
],
"summary": "build scalable search applications using Elasticsearch without having to do complex low-level programming or understand advanced data science algorithms",
"publish_date": "2015-12-03",
"num_reviews": 18,
"publisher": "manning"
}
}
]
}

注意:以上结果中文档4(_id=4)匹配的原因是guide在summary存在。

3、 Boosting提升某字段得分的检索( Boosting)

由于我们正在多个字段进行搜索,我们可能希望提高某一字段的得分。 在下面的例子中,我们将“摘要”字段的得分提高了3倍,以增加“摘要”字段的重要性,从而提高文档 4 的相关性。

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
GET bookdb_index/book/_search
{
"query": {
"multi_match": {
"query": "elasticsearch guide",
"fields": ["title", "summary^3"]
}
},
"_source": ["title", "summary", "publish_date"]
}

[Results]
"hits": {
"total": 3,
"max_score": 3.9835935,
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "4",
"_score": 3.9835935,
"_source": {
"summary": "Comprehensive guide to implementing a scalable search engine using Apache Solr",
"title": "Solr in Action",
"publish_date": "2014-04-05"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "3",
"_score": 3.1001682,
"_source": {
"summary": "build scalable search applications using Elasticsearch without having to do complex low-level programming or understand advanced data science algorithms",
"title": "Elasticsearch in Action",
"publish_date": "2015-12-03"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "1",
"_score": 2.0281231,
"_source": {
"summary": "A distibuted real-time search and analytics engine",
"title": "Elasticsearch: The Definitive Guide",
"publish_date": "2015-02-07"
}
}
]
}

注意:Boosting不仅意味着计算得分乘法以增加因子。 实际的提升得分值是通过归一化和一些内部优化。参考 Elasticsearch guide查看更多

4、Bool检索( Bool Query)

可以使用 AND / OR / NOT 运算符来微调我们的搜索查询,以提供更相关或指定的搜索结果。

在搜索API中是通过bool查询来实现的。 bool查询接受 must 参数(等效于AND),一个 must_not 参数(相当于NOT)或者一个 should 参数(等同于OR)。

例如,如果我想在标题中搜索一本名为 “Elasticsearch” 或 “Solr” 的书,AND由 “clinton gormley” 创作,但NOT由 “radu gheorge” 创作

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
GET bookdb_index/book/_search
{
"query": {
"bool": {
"must": [
{
"bool": {
"should": [
{"match": {"title": "Elasticsearch"}},
{"match": {"title": "Solr"}}
]
}
},
{
"match": {"authors": "clinton gormely"}
}
],
"must_not": [
{
"match": {"authors": "radu gheorge"}
}
]
}
}
}

[Results]
"hits": {
"total": 1,
"max_score": 2.0749094,
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "1",
"_score": 2.0749094,
"_source": {
"title": "Elasticsearch: The Definitive Guide",
"authors": [
"clinton gormley",
"zachary tong"
],
"summary": "A distibuted real-time search and analytics engine",
"publish_date": "2015-02-07",
"num_reviews": 20,
"publisher": "oreilly"
}
}
]
}

关于bool查询中的should, 有两种情况:

  • 当should的同级存在must的时候,should中的条件可以满足也可以不满足,满足的越多得分越高
  • 当没有must的时候,默认should中的条件至少要满足一个

注意:您可以看到,bool查询可以包含任何其他查询类型,包括其他布尔查询,以创建任意复杂或深度嵌套的查询

5、 Fuzzy 模糊检索( Fuzzy Queries)

在 Match检索 和多匹配检索中可以启用模糊匹配来捕捉拼写错误。 基于与原始词的 Levenshtein 距离来指定模糊度

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
GET bookdb_index/book/_search
{
"query": {
"multi_match": {
"query": "comprihensiv guide",
"fields": ["title","summary"],
"fuzziness": "AUTO"
}
},
"_source": ["title","summary","publish_date"],
"size": 2
}

[Results]
"hits": {
"total": 2,
"max_score": 2.4344182,
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "4",
"_score": 2.4344182,
"_source": {
"summary": "Comprehensive guide to implementing a scalable search engine using Apache Solr",
"title": "Solr in Action",
"publish_date": "2014-04-05"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "1",
"_score": 1.2871116,
"_source": {
"summary": "A distibuted real-time search and analytics engine",
"title": "Elasticsearch: The Definitive Guide",
"publish_date": "2015-02-07"
}
}
]
}

“AUTO” 的模糊值相当于当字段长度大于5时指定值2。但是,设置80%的拼写错误的编辑距离为1,将模糊度设置为1可能会提高整体搜索性能。 有关更多信息, Typos and Misspellingsch

6、 Wildcard Query 通配符检索

通配符查询允许您指定匹配的模式,而不是整个词组(term)检索

  • ? 匹配任何字符
    • 匹配零个或多个字符

举例,要查找具有以 “t” 字母开头的作者的所有记录,如下所示

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
GET bookdb_index/book/_search
{
"query": {
"wildcard": {
"authors": {
"value": "t*"
}
}
},
"_source": ["title", "authors"],
"highlight": {
"fields": {
"authors": {}
}
}
}

[Results]
"hits": {
"total": 3,
"max_score": 1,
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "1",
"_score": 1,
"_source": {
"title": "Elasticsearch: The Definitive Guide",
"authors": [
"clinton gormley",
"zachary tong"
]
},
"highlight": {
"authors": [
"zachary <em>tong</em>"
]
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "2",
"_score": 1,
"_source": {
"title": "Taming Text: How to Find, Organize, and Manipulate It",
"authors": [
"grant ingersoll",
"thomas morton",
"drew farris"
]
},
"highlight": {
"authors": [
"<em>thomas</em> morton"
]
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "4",
"_score": 1,
"_source": {
"title": "Solr in Action",
"authors": [
"trey grainger",
"timothy potter"
]
},
"highlight": {
"authors": [
"<em>trey</em> grainger",
"<em>timothy</em> potter"
]
}
}
]
}

7、正则表达式检索( Regexp Query)

正则表达式能指定比通配符检索更复杂的检索模式,举例如下:

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
POST bookdb_index/book/_search
{
"query": {
"regexp": {
"authors": "t[a-z]*y"
}
},
"_source": ["title", "authors"],
"highlight": {
"fields": {
"authors": {}
}
}
}

[Results]
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "4",
"_score": 1,
"_source": {
"title": "Solr in Action",
"authors": [
"trey grainger",
"timothy potter"
]
},
"highlight": {
"authors": [
"<em>trey</em> grainger",
"<em>timothy</em> potter"
]
}
}
]
}

8、匹配短语检索( Match Phrase Query)

匹配短语查询要求查询字符串中的所有词都存在于文档中,按照查询字符串中指定的顺序并且彼此靠近

默认情况下,这些词必须完全相邻,但您可以指定偏离值(slop value),该值指示在仍然考虑文档匹配的情况下词与词之间的偏离值。

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
GET bookdb_index/book/_search
{
"query": {
"multi_match": {
"query": "search engine",
"fields": ["title", "summary"],
"type": "phrase",
"slop": 3
}
},
"_source": [ "title", "summary", "publish_date" ]
}

[Results]
"hits": {
"total": 2,
"max_score": 0.88067603,
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "4",
"_score": 0.88067603,
"_source": {
"summary": "Comprehensive guide to implementing a scalable search engine using Apache Solr",
"title": "Solr in Action",
"publish_date": "2014-04-05"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "1",
"_score": 0.51429313,
"_source": {
"summary": "A distibuted real-time search and analytics engine",
"title": "Elasticsearch: The Definitive Guide",
"publish_date": "2015-02-07"
}
}
]
}

注意:在上面的示例中,对于非短语类型查询,文档_id 1通常具有较高的分数,并且显示在文档_id 4之前,因为其字段长度较短。

然而,作为一个短语查询,词与词之间的接近度被考虑在内,所以文档_id 4分数更好

9、匹配词组前缀检索

匹配词组前缀查询在查询时提供搜索即时类型或 “相对简单” “的自动完成版本,而无需以任何方式准备数据。

像match_phrase查询一样,它接受一个斜率参数,使得单词的顺序和相对位置没有那么 “严格”。 它还接受max_expansions参数来限制匹配的条件数以减少资源强度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET bookdb_index/book/_search
{
"query": {
"match_phrase_prefix": {
"summary": {
"query": "search en",
"slop": 3,
"max_expansions": 10
}
}
},
"_source": ["title","summary","publish_date"]
}

注意:查询时间搜索类型具有性能成本。 一个更好的解决方案是将时间作为索引类型。 更多相关API查询 Completion Suggester API 或者 Edge-Ngram filters 。

10、字符串检索( Query String)

query_string查询提供了以简明的简写语法执行多匹配查询 multi_match queries ,布尔查询 bool queries ,提升得分 boosting ,模糊匹配 fuzzy matching ,通配符 wildcards ,正则表达式 regexp 和范围查询 range queries 的方式。

在下面的例子中,我们对 “search algorithm” 一词执行模糊搜索,其中一本作者是 “grant ingersoll” 或 “tom morton”。 我们搜索所有字段,但将提升应用于文档2的摘要字段

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
GET bookdb_index/book/_search
{
"query": {
"query_string": {
"query": "(saerch~1 algorithm~1) AND (grant ingersoll) OR (tom morton)",
"fields": ["summary^2","title","authors","publisher"]
}
},
"_source": ["title","summary","authors"],
"highlight": {
"fields": {
"summary": {}
}
}
}

[Results]
"hits": {
"total": 1,
"max_score": 3.571021,
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "2",
"_score": 3.571021,
"_source": {
"summary": "organize text using approaches such as full-text search, proper name recognition, clustering, tagging, information extraction, and summarization",
"title": "Taming Text: How to Find, Organize, and Manipulate It",
"authors": [
"grant ingersoll",
"thomas morton",
"drew farris"
]
},
"highlight": {
"summary": [
"organize text using approaches such as full-text <em>search</em>, proper name recognition, clustering, tagging"
]
}
}
]
}

11、简化的字符串检索 (Simple Query String)

simple_query_string 查询是 query_string 查询的一个版本,更适合用于暴露给用户的单个搜索框, 因为它分别用 + / | / - 替换了 AND / OR / NOT 的使用,并放弃查询的无效部分,而不是在用户出错时抛出异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GET bookdb_index/book/_search
{
"query": {
"simple_query_string": {
"query": "(saerch~1 algorithm~1) + (grant ingersoll) | (tom morton)",
"fields": ["summary^2","title","authors","publisher"]
}
},
"_source": ["title","summary","authors"],
"highlight": {
"fields": {
"summary": {}
}
}
}

[Results]
# 结果同上


12、Term/Terms检索(指定字段检索)

上面1-11小节的例子是全文搜索的例子。 有时我们对结构化搜索更感兴趣,我们希望在其中找到完全匹配并返回结果

在下面的例子中,我们搜索 Manning Publications 发布的索引中的所有图书(借助 term和terms查询 )

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
GET bookdb_index/book/_search
{
"query": {
"term": {
"publisher": {
"value": "manning"
}
}
},
"_source" : ["title","publish_date","publisher"]
}

[Results]
"hits": {
"total": 3,
"max_score": 0.35667494,
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "2",
"_score": 0.35667494,
"_source": {
"publisher": "manning",
"title": "Taming Text: How to Find, Organize, and Manipulate It",
"publish_date": "2013-01-24"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "3",
"_score": 0.35667494,
"_source": {
"publisher": "manning",
"title": "Elasticsearch in Action",
"publish_date": "2015-12-03"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "4",
"_score": 0.35667494,
"_source": {
"publisher": "manning",
"title": "Solr in Action",
"publish_date": "2014-04-05"
}
}
]
}

Multiple terms可指定多个关键词进行检索

1
2
3
4
5
6
7
8
9
GET bookdb_index/book/_search
{
"query": {
"terms": {
"publisher": ["oreilly", "manning"]
}
}
}

13、Term排序检索-(Term Query - Sorted)

Term查询和其他查询一样,轻松的实现排序。多级排序也是允许的

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
GET bookdb_index/book/_search
{
"query": {
"term": {
"publisher": {
"value": "manning"
}
}
},
"_source" : ["title","publish_date","publisher"],
"sort": [{"publisher.keyword": { "order": "desc"}},
{"title.keyword": {"order": "asc"}}]
}

[Results]
"hits": {
"total": 3,
"max_score": null,
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "3",
"_score": null,
"_source": {
"publisher": "manning",
"title": "Elasticsearch in Action",
"publish_date": "2015-12-03"
},
"sort": [
"manning",
"Elasticsearch in Action"
]
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "4",
"_score": null,
"_source": {
"publisher": "manning",
"title": "Solr in Action",
"publish_date": "2014-04-05"
},
"sort": [
"manning",
"Solr in Action"
]
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "2",
"_score": null,
"_source": {
"publisher": "manning",
"title": "Taming Text: How to Find, Organize, and Manipulate It",
"publish_date": "2013-01-24"
},
"sort": [
"manning",
"Taming Text: How to Find, Organize, and Manipulate It"
]
}
]
}

注意:Elasticsearch 6.x 全文搜索用text类型的字段,排序用不用 text 类型的字段

14、范围检索(Range query)

另一个结构化检索的例子是范围检索。下面的举例中,我们检索了2015年发布的书籍。

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
GET bookdb_index/book/_search
{
"query": {
"range": {
"publish_date": {
"gte": "2015-01-01",
"lte": "2015-12-31"
}
}
},
"_source" : ["title","publish_date","publisher"]
}

[Results]
"hits": {
"total": 2,
"max_score": 1,
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "1",
"_score": 1,
"_source": {
"publisher": "oreilly",
"title": "Elasticsearch: The Definitive Guide",
"publish_date": "2015-02-07"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "3",
"_score": 1,
"_source": {
"publisher": "manning",
"title": "Elasticsearch in Action",
"publish_date": "2015-12-03"
}
}
]
}

注意:范围查询适用于日期,数字和字符串类型字段

15、过滤检索(Filtered query)

(5.0版本起已不再存在,不必关注)

过滤的查询允许您过滤查询的结果。 如下的例子,我们在标题或摘要中查询名为“Elasticsearch”的图书,但是我们希望将结果过滤到只有20个或更多评论的结果。

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
POST /bookdb_index/book/_search
{
"query": {
"filtered": {
"query" : {
"multi_match": {
"query": "elasticsearch",
"fields": ["title","summary"]
}
},
"filter": {
"range" : {
"num_reviews": {
"gte": 20
}
}
}
}
},
"_source" : ["title","summary","publisher", "num_reviews"]
}


[Results]
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "1",
"_score": 0.5955761,
"_source": {
"summary": "A distibuted real-time search and analytics engine",
"publisher": "oreilly",
"num_reviews": 20,
"title": "Elasticsearch: The Definitive Guide"
}
}
]

注意:已过滤的查询不要求存在要过滤的查询。 如果没有指定查询,则运行 match_all 查询,基本上返回索引中的所有文档,然后对其进行过滤。 实际上,首先运行过滤器,减少需要查询的表面积。 此外,过滤器在第一次使用后被缓存,这使得它非常有效

更新: 已筛选的查询已推出的Elasticsearch 5.X版本中移除,有利于布尔查询。 这是与上面重写的使用bool查询相同的示例。 返回的结果是完全一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
GET bookdb_index/book/_search
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "elasticsearch",
"fields": ["title","summary"]
}
}
],
"filter": {
"range": {
"num_reviews": {
"gte": 20
}
}
}
}
},
"_source" : ["title","summary","publisher", "num_reviews"]
}

16、多个过滤器检索(Multiple Filters)

(5.x不再支持,无需关注) 多个过滤器可以通过使用布尔过滤器进行组合。

在下一个示例中,过滤器确定返回的结果必须至少包含20个评论,不得在2015年之前发布,并且应该由oreilly发布

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
POST /bookdb_index/book/_search
{
"query": {
"filtered": {
"query" : {
"multi_match": {
"query": "elasticsearch",
"fields": ["title","summary"]
}
},
"filter": {
"bool": {
"must": {
"range" : { "num_reviews": { "gte": 20 } }
},
"must_not": {
"range" : { "publish_date": { "lte": "2014-12-31" } }
},
"should": {
"term": { "publisher": "oreilly" }
}
}
}
}
},
"_source" : ["title","summary","publisher", "num_reviews", "publish_date"]
}


[Results]
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "1",
"_score": 0.5955761,
"_source": {
"summary": "A distibuted real-time search and analytics engine",
"publisher": "oreilly",
"num_reviews": 20,
"title": "Elasticsearch: The Definitive Guide",
"publish_date": "2015-02-07"
}
}
]

17、 Function 得分:Field值因子( Function Score: Field Value Factor)

可能有一种情况,您想要将文档中特定字段的值纳入相关性分数的计算。 这在您希望基于其受欢迎程度提升文档的相关性的情况下是有代表性的场景

在我们的例子中,我们希望增加更受欢迎的书籍(按评论数量判断)。 这可以使用field_value_factor函数得分

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
GET bookdb_index/book/_search
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "search engine",
"fields": ["title","summary"]
}
},
"field_value_factor": {
"field": "num_reviews",
"modifier": "log1p",
"factor": 2
}
}
},
"_source": ["title", "summary", "publish_date", "num_reviews"]
}

[Results]
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "1",
"_score": 1.5694137,
"_source": {
"summary": "A distibuted real-time search and analytics engine",
"num_reviews": 20,
"title": "Elasticsearch: The Definitive Guide",
"publish_date": "2015-02-07"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "4",
"_score": 1.4725765,
"_source": {
"summary": "Comprehensive guide to implementing a scalable search engine using Apache Solr",
"num_reviews": 23,
"title": "Solr in Action",
"publish_date": "2014-04-05"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "3",
"_score": 0.14181662,
"_source": {
"summary": "build scalable search applications using Elasticsearch without having to do complex low-level programming or understand advanced data science algorithms",
"num_reviews": 18,
"title": "Elasticsearch in Action",
"publish_date": "2015-12-03"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "2",
"_score": 0.13297246,
"_source": {
"summary": "organize text using approaches such as full-text search, proper name recognition, clustering, tagging, information extraction, and summarization",
"num_reviews": 12,
"title": "Taming Text: How to Find, Organize, and Manipulate It",
"publish_date": "2013-01-24"
}
}
]
}

注1:我们可以运行一个常规的multi_match查询,并按num_reviews字段排序,但是我们失去了相关性得分的好处。
注2:有许多附加参数可以调整对原始相关性分数 (如“ modifier ”,“ factor ”,“boost_mode”等)的增强效果的程度。
详见 Elasticsearch guide.

18、 Function 得分:衰减函数( Function Score: Decay Functions )

假设,我们不是想通过一个字段的值逐渐增加得分,以获取理想的结果。 举例:价格范围、数字字段范围、日期范围。 在我们的例子中,我们正在搜索2014年6月左右出版的“ search engines ”的书籍。

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
GET bookdb_index/book/_search
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "search engine",
"fields": ["title", "summary"]
}
},
"functions": [
{
"exp": {
"publish_date": {
"origin": "2014-06-15",
"scale": "30d",
"offset": "7d"
}
}
}
],
"boost_mode": "replace"
}
},
"_source": ["title", "summary", "publish_date", "num_reviews"]
}

[Results]
"hits": {
"total": 4,
"max_score": 0.22793062,
"hits": [
{
"_index": "bookdb_index",
"_type": "book",
"_id": "4",
"_score": 0.22793062,
"_source": {
"summary": "Comprehensive guide to implementing a scalable search engine using Apache Solr",
"num_reviews": 23,
"title": "Solr in Action",
"publish_date": "2014-04-05"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "1",
"_score": 0.0049215667,
"_source": {
"summary": "A distibuted real-time search and analytics engine",
"num_reviews": 20,
"title": "Elasticsearch: The Definitive Guide",
"publish_date": "2015-02-07"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "2",
"_score": 0.000009612435,
"_source": {
"summary": "organize text using approaches such as full-text search, proper name recognition, clustering, tagging, information extraction, and summarization",
"num_reviews": 12,
"title": "Taming Text: How to Find, Organize, and Manipulate It",
"publish_date": "2013-01-24"
}
},
{
"_index": "bookdb_index",
"_type": "book",
"_id": "3",
"_score": 0.0000049185574,
"_source": {
"summary": "build scalable search applications using Elasticsearch without having to do complex low-level programming or understand advanced data science algorithms",
"num_reviews": 18,
"title": "Elasticsearch in Action",
"publish_date": "2015-12-03"
}
}
]
}

19、Function得分:脚本得分( Function Score: Script Scoring )

在内置计分功能不符合您需求的情况下,可以选择指定用于评分的Groovy脚本

在我们的示例中,我们要指定一个考虑到publish_date的脚本,然后再决定考虑多少评论。 较新的书籍可能没有这么多的评论,所以他们不应该为此付出“代价”

得分脚本如下所示:

1
2
3
4
5
6
7
8
9
10
publish_date = doc['publish_date'].value
num_reviews = doc['num_reviews'].value

if (publish_date > Date.parse('yyyy-MM-dd', threshold).getTime()) {
my_score = Math.log(2.5 + num_reviews)
} else {
my_score = Math.log(1 + num_reviews)
}
return my_score

要动态使用评分脚本,我们使用script_score参数

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
GET /bookdb_index/book/_search
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "search engine",
"fields": ["title","summary"]
}
},
"functions": [
{
"script_score": {
"script": {
"params": {
"threshold": "2015-07-30"
},
"lang": "groovy",
"source": "publish_date = doc['publish_date'].value; num_reviews = doc['num_reviews'].value; if (publish_date > Date.parse('yyyy-MM-dd', threshold).getTime()) { return log(2.5 + num_reviews) }; return log(1 + num_reviews);"
}
}
}
]
}
},
"_source": ["title","summary","publish_date", "num_reviews"]
}

注1:要使用动态脚本,必须为config / elasticsearch.yml文件中的Elasticsearch实例启用它。 也可以使用已经存储在Elasticsearch服务器上的脚本。 查看 Elasticsearch reference docs 以获取更多信息。
注2: JSON不能包含嵌入的换行符,因此分号用于分隔语句。
原文作者: by Tim Ojo Aug. 05, 16 · Big Data Zone
原文地址:dzone.com/articles/23…

注意:ES6.3 怎样启用 groovy 脚本?配置未成功
script.allowed_types: inline & script.allowed_contexts: search, update

Java API 实现

Java API 实现上面的查询,代码见 github.com/whirlys/ela…

作者:铭毅天下

原文地址:
http://blog.csdn.net/laoyang360/article/details/75094457

java8 常用代码

1. 使用java8 提取出 list 中 bean 的某一属性

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
public static void main(String[] args) {
List<Student> stuList = new ArrayList<Student>();
Student st1 = new Student("123","aaa");
Student st2 = new Student("234","bbb");
Student st3 = new Student("345","ccc");
Student st4 = new Student("345","ccc");
stuList.add(st1);
stuList.add(st2);
stuList.add(st3);
stuList.add(st4);
//1.提取出list对象中的一个属性
List<String> stIdList1 = stuList.stream()
.map(Student::getId)
.collect(Collectors.toList());
stIdList1.forEach(s -> System.out.print(s+" "));
System.out.println();
System.out.println("----------");

//2.提取出list对象中的一个属性并去重
List<String> stIdList2 = stuList.stream()
.map(Student::getId).distinct()
.collect(Collectors.toList());
stIdList2.forEach(s -> System.out.print(s+" "));
/* 结果:
123 234 345 345
----------
123 234 345
*/
}

2. 使用 java8 提取出 list 中 bean 的两个属性转换为Map

1
2
3
List<DictVO> dictVOList = tSysDictService.findByDictType("dataset_catalog_icon");
Map<String, String> iconMap = dictVOList.stream()
.collect(Collectors.toMap(DictVO::getText, DictVO::getValue));

3. 使用 java8 根据某个属性倒序排序

1
2
list = list.stream().sorted(Comparator.comparing(PromotionForHomeDto::getCreateTime).reversed())
.collect(Collectors.toList());

3. List 转 Set

Java8 List<对象> 转 Set、Map(高级)、排序、分组、统计

1
2
3
4
5
System.out.println("----------------普通List---------------");
normalList.forEach(System.out::println);
System.out.println("----------------普通List转Set---------------");
Set<Integer> normalSet = normalList.stream().map(Student::getClassNo).collect(Collectors.toSet());
normalSet.forEach(System.out::println);

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
----------------普通List---------------
Student{id=1, name='Emma', score='A', classNo=701}
Student{id=2, name='Larissa', score='S', classNo=701}
Student{id=3, name='Sophia', score='B', classNo=701}
Student{id=4, name='Ashley', score='B', classNo=702}
Student{id=5, name='May', score='C', classNo=702}
Student{id=6, name='Hailey', score='D', classNo=702}
Student{id=7, name='Kelly', score='S', classNo=703}
Student{id=8, name='Amy', score='A', classNo=703}
Student{id=9, name='Wesley', score='C', classNo=703}
----------------普通List转Set---------------
701
702
703

4. java8 中根据判断删除列表list中的元素

我们知道,在java8出lambda表达式之前,是不支持在循环中直接对list进行删除的。但是java8的新特性lambda表达式,帮我们实现了这个功能:

1
2
3
4
5
6
7
List<String> lists = new ArrayList<>();
lists.add("a");
lists.add("b");
lists.add("c");

//使用removeIf方法,->里的是判断条件,如果符合这个条件就删除。这里会删除带有c的元素
lists.removeIf(s -> s.contains("c"));

java8新特性大大的简化了我们的代码,使用更加的方便。

5. java8 获取 lsit 中bean 的某一属性最大的对象

1
Student student = studentList.stream().max(Comparator.comparing(Student::getClassCount)).get();

6. java8 计算代码运行时间

java8之前是这样计算代码运行时间的

1
2
3
4
long startTime=System.currentTimeMillis();   //获取开始时间  
doSomeThing(); //测试的代码段
long endTime=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间: "+(end-start)+"ms");

java8之后可以使用Instant获取时间戳来计算代码运行时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
	public static void main(String[] args) {
Instant start = Instant.now();

LongStream.rangeClosed( 0,110 )
//并行流
.parallel()
.reduce( 0,Long::sum );

LongStream.rangeClosed( 0,110 )
//顺序流
.sequential()
.reduce( 0,Long::sum );

Instant end = Instant.now();
System.out.println("耗费时间"+ Duration.between( start,end ).toMillis());
}

Redis 数据类型及应用场景

原文地址:https://segmentfault.com/a/1190000012212663

作者:waterandair

一、 redis 特点

  • 所有数据存储在内存中,高速读写
  • 提供丰富多样的数据类型:string、 hash、 set、 sorted set、bitmap、hyperloglog
  • 提供了 AOF 和 RDB 两种数据的持久化保存方式,保证了 Redis 重启后数据不丢失
  • Redis 的所有操作都是原子性的,还支持对几个操作合并后的原子性操作,支持事务

 通常我们都把数据存到关系型数据库中,但为了提升应用的性能,我们应该把访频率高且不会经常变动的数据缓存到内存中。。Redis 没有像 MySQL 这类关系型数据库那样强大的查询功能,需要考虑如何把关系型数据库中的数据,合理的对应到缓存的 key-value 数据结构中。

二、 设计 Redis Key

分段设计法

  使用冒号把 key 中要表达的多种含义分开表示,步骤如下:

  1. 把表名转化为 key 前缀
  2. 主键名(或其他常用于搜索的字段)
  3. 主键值
  4. 要存储的字段。

eg. 用户表(user)

id name email
1 zj 156577812@qq.com
2 ai 156577813@qq.com

这个简单的表可能经常会有这个的需求:>根据用户 id 查询用户邮箱地址,可以选择把邮箱地址这个数据存到 redis 中:

1
2
set user:id:1:email 156577812@qq.com;
set user:id:2:email 156577812@qq.com;

三、 String数据类型的应用场景

1. 简介

  string 类型是 Redis 中最基本的数据类型,最常用的数据类型,甚至被很多玩家当成 redis 唯一的数据类型去使用。string 类型在 redis 中是二进制安全(binary safe)的,这意味着 string 值关心二进制的字符串,不关心具体格式,你可以用它存储 json 格式或 JPEG 图片格式的字符串。   

2. 数据模型

  string 类型是基本的 Key-Value 结构,Key 是某个数据在 Redis 中的唯一标识,Value 是具体的数据。

Key Value
‘name’ ‘redis’
‘type’ ‘string’

3. 应用场景

(1) 存储 MySQL 中某个字段的值

把 key 设计为 表名:主键名:主键值:字段名
eg.

1
set user:id:1:email 156577812@qq.com
(2) 存储对象

string 类型支持任何格式的字符串,应用最多的就是存储 json 或其他对象格式化的字符串。(这种场景下推荐使用 hash 数据类型)

1
set user:id:1 '[{"id":1,"name":"zj","email":"156577812@qq.com"},{"id":1,"name":"zj","email":"156577812@qq.com"}]'
(3) 生成自增 id

当 redis 的 string 类型的值为整数形式时,redis 可以把它当做是整数一样进行自增(incr)自减(decr)操作。由于 redis 所有的操作都是原子性的,所以不必担心多客户端连接时可能出现的事务问题。

四、hash 数据类型的应用场景

1. 简介

  hash 类型很像一个关系型数据库的数据表,hash 的 Key 是一个唯一值,Value 部分是一个 hashmap 的结构。   

2. 数据模型

  假设有一张数据库表如下:

id name type
1 redis hash

  如果要用 redis 的 hash 结构存储,数据模型如下:

clipboard.png

  hash数据类型在存储上述类型的数据时具有比 string 类型更灵活、更快的优势,具体的说,使用 string 类型存储,必然需要转换和解析 json 格式的字符串,即便不需要转换,在内存开销方面,还是 hash 占优势。   

3. 应用场景

hash 类型十分适合存储对象类数据,相对于在 string 中介绍的把对象转化为 json 字符串存储,hash 的结构可以任意添加或删除‘字段名’,更加高效灵活。

1
hmset user:1 name zj email 156577812@qq.com

五、list 数据类型的应用场景

1. 简介

  list 是按照插入顺序排序的字符串链表,可以在头部和尾部插入新的元素(双向链表实现,两端添加元素的时间复杂度为 O(1))。插入元素时,如果 key 不存在,redis 会为该 key 创建一个新的链表,如果链表中所有的元素都被移除,该 key 也会从 redis 中移除。

2. 数据模型

clipboard.png

  常见操作时用 lpush 命令在 list 头部插入元素, 用 rpop 命令在 list 尾取出数据。   

3. 应用场景

(1) 消息队列

  redis 的 list 数据类型对于大部分使用者来说,是实现队列服务的最经济,最简单的方式。   

(2) “最新内容”

因为 list 结构的数据查询两端附近的数据性能非常好,所以适合一些需要获取最新数据的场景,比如新闻类应用的 “最近新闻”。   

4.优化建议

(1) list 是链表结构,所有如果在头部和尾部插入数据,性能会非常高,不受链表长度的影响;但如果在链表中插入数据,性能就会越来越差。

六、set 数据类型的应用场景

1. 简介

  set 数据类型是一个集合(没有排序,不重复),可以对 set 类型的数据进行添加、删除、判断是否存在等操作(时间复杂度是 O(1) )
  set 集合不允许数据重复,如果添加的数据在 set 中已经存在,将只保留一份。
  set 类型提供了多个 set 之间的聚合运算,如求交集、并集、补集,这些操作在 redis 内部完成,效率很高。

2. 数据模型

clipboard.png

3. 应用场景

  set 类型的特点是——不重复且无序的一组数据,并且具有丰富的计算功能,在一些特定的场景中可以高效的解决一般关系型数据库不方便做的工作。

1. “共同好友列表”

  社交类应用中,获取两个人或多个人的共同好友,两个人或多个人共同关注的微博这样类似的功能,用 MySQL 的话操作很复杂,可以把每个人的好友 id 存到集合中,获取共同好友的操作就可以简单到一个取交集的命令就搞定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 这里为了方便阅读,把 id 替换成姓名
sadd user:wade james melo paul kobe
sadd user:james wade melo paul kobe
sadd user:paul wade james melo kobe
sadd user:melo wade james paul kobe

// 获取 wade 和 james 的共同好友
sinter user:wade user:james
/* 输出:
* 1) "kobe"
* 2) "paul"
* 3) "melo"
*/

// 获取香蕉四兄弟的共同好友
sinter user:wade user:james user:paul user:melo
/* 输出:
* 1) "kobe"
*/

/*
类似的需求还有很多 , 必须把每个标签下的文章 id 存到集合中,可以很容易的求出几个不同标签下的共同文章;
把每个人的爱好存到集合中,可以很容易的求出几个人的共同爱好。
*/

七、sorted set 数据类型的应用场景

1.简介

  在 set 的基础上给集合中每个元素关联了一个分数,往有序集合中插入数据时会自动根据这个分数排序。

2.应用场景

  在集合类型的场景上加入排序就是有序集合的应用场景了。比如根据好友的“亲密度”排序显示好友列表。

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
// 用元素的分数(score)表示与好友的亲密度
zadd user:kobe 80 james 90 wade 85 melo 90 paul

// 根据“亲密度”给好友排序
zrevrange user:kobe 0 -1

/**
* 输出:
* 1) "wade"
* 2) "paul"
* 3) "melo"
* 4) "james"
*/

// 增加好友的亲密度
zincrby user:kobe 15 james

// 再次根据“亲密度”给好友排序
zrevrange user:kobe 0 -1

/**
* 输出:
* 1) "james"
* 2) "wade"
* 3) "paul"
* 2) "melo"

JSON Web Token 入门教程

作者:阮一峰
原文链接:http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案,本文介绍它的原理和用法。

一、跨域认证的问题

互联网服务离不开用户认证。一般流程是下面这样。

1
2
3
4
5
1、用户向服务器发送用户名和密码
2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
3、服务器向用户返回一个 session_id,写入用户 Cookie。
4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

这种模式的问题在于,扩展性(scaling)不好。单机当然没有问题,如果是服务器集群,或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。

举例来说,A 网站和 B 网站是同一家公司的关联服务。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录,请问怎么实现?

一种解决方案是 session 数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是工程量比较大。另外,持久层万一挂了,就会单点失败。

另一种方案是服务器索性不保存 session 数据了,所有数据都保存在客户端,每次请求都发回服务器。JWT 就是这种方案的一个代表。

二、JWT 的原理

JWT 的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样。

1
2
3
4
5
{
"姓名": "张三",
"角色": "管理员",
"到期时间": "2018年7月1日0点0分"
}

以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名(详见后文)。

服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

三、JWT 的数据结构

实际的 JWT 大概就像下面这样。

它是一个很长的字符串,中间用点(.)分隔成三个部分。注意,JWT 内部是没有换行的,这里只是为了便于展示,将它写成了几行。

JWT 的三个部分依次如下。

  • Header(头部)
  • Payload(负载)
  • Signature(签名)

写成一行,就是下面的样子。

1
Header.Payload.Signature

一个 JWT 生成的 Token 格式为:

1
token = encodeBase64(header) + '.' + encodeBase64(payload) + '.' + encodeBase64(signature)

下面依次介绍这三个部分。

3.1 Header

Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。

1
2
3
4
{
"alg": "HS256",
"typ": "JWT"
}

上面代码中,alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT

最后,将上面的 JSON 对象使用 Base64URL 算法(详见后文)转成字符串。

3.2 Payload

Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。

  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主题
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号

除了官方字段,你还可以在这个部分定义私有字段,下面就是一个例子。

1
2
3
4
5
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}

注意,JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。

这个 JSON 对象也要使用 Base64URL 算法转成字符串。

3.3 Signature

Signature 部分是对前两部分的签名,防止数据篡改。

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

1
2
3
4
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用”点”(.)分隔,就可以返回给用户。

3.4 Base64URL

前面提到,Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+/=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-/替换成_ 。这就是 Base64URL 算法。

四、JWT 的使用方式

客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。

此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面。

1
Authorization: Bearer <token>

另一种做法是,跨域的时候,JWT 就放在 POST 请求的数据体里面。

五、JWT 的几个特点

(1)JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。

(2)JWT 不加密的情况下,不能将秘密数据写入 JWT。

(3)JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。

(4)JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。

(5)JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。

(6)为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

六、参考链接

(完)

别让自己“墙”了自己

转载自:陈皓
链接:https://coolshell.cn/articles/20276.html

小结:

别把自己最宝贵的青春放在了很烂的项目上,就算能用一些新的技术,也只能算是自娱自乐,在实验室中玩玩具罢了。

野、环境和舞台,对一个人的限制是非常大的。

偏见和不开放,对一个人的限制是真正有毁灭性的。

不限制自己,别把自己封闭起来,“艺多不压身”,有什么就学什么,有更高的就去向更高的迈进

尽最大可能出去经历一下世界最顶尖的公司

别限制了自己

  • 做有价值的事
  • 扩大自己的眼界,开放自己的内心。你的英文语言能力对你能不能融入世界是起决定性的作用。你的视野决定了你的知不知道要去哪,你的开放决定了你想不想去。
  • 站在更高的维度。
  • 精于计算得失。精于计算得失的,就懂得什么是投资,不懂的只会投机。对于赚钱,你可以投机,但是对于自己最好还是投资。
  • 勇于跳出传统的束缚

这一两周与几个朋友聊天,有年轻的90后,也有大叔级的70后,这些人在我看来都是很有能力的人,但是一些喜好过于强烈,让我不经意地回顾了我工作20年来身边的人,有发展得好的,也有发展的不好的,有些人是很可惜的,因为限制他们的不是其它人,也不是环境,而是自己,所以,很想写下这篇文章。(注:这篇文章可能会是一篇说教的文章,所以,可能会让你看着犯困,所以,我会尽量地短一些,而且尽可能多讲故事,少道理,这里的故事,全是真实发生的)

几个故事

2019年年初,我面试了一个很年轻的小伙子(93/94年出生),这个小伙子特别有灵性,也很聪明,计算机专业出身,也很喜欢技术,基础和学习能力也很好。在我这20年来认识的人中,如果他能呆在北京、上海、深圳这样的城市,我保证不出三年,他会成为他们同龄人中非常出色的技术人员,如果有个好的舞台有一个好的团队带他,他的未来会非常成功。然而,这个小伙子有两大喜好:1)只愿(或是说被迫)呆在一个毫无IT的环境的三/四线城市,2)对技术有非常大的偏好,只喜欢Go语言,非常不喜欢其它的语言,比如:Java(离开Java的世界,基本上离开了做架构的世界(相关解释见文末))。

他的这两个喜好,足以让一个未来会很优秀的人毁掉,因为,这个时代没有限制他,他的能力也没有限制他,但是他的意识完完全全地限制了他。

  • 他把自己最宝贵的青春放在了很烂的项目上,就算能用一些新的技术,他也只能算是自娱自乐,在实验室中玩玩具罢了。
  • 他把自己的技术栈封闭起来,而直接放弃了这个时代最具工业化的技术Java,对于一个好的程序员来说,同时掌握几门语言和技术完全是没什么问题,但是自己封闭了自己的视野。

实在是非常可惜,我本来是可以为他介绍到一些很不错的公司的,但是他这样的习性,等于自己把自己未来的门给关上了,虽然我跟他长谈过,但是我也没有办法叫醒不想醒的人……

  • 视野、环境和舞台,对一个人的限制是非常大的。井蛙不知道大海,被空间维度所限制;夏虫不知道冬天,是被时间维度所限制;圈养的动物没有斗志,是被自己意识所限制。
  • 偏见和不开放,对一个人的限制是真正有毁灭性的。主动让自己成为一个瞎子和聋子,主动把自己的能力阉割掉,这是一件令人痛心的事。想想大清的闭关锁国是如何让亚洲第一的北洋水师给毁掉的……

我还有个同学,他的技术并不差,就算呆在昆明这种很落后的地方,他也非常地好学,学习英文,学习各种新技术,对技术没有任何的偏好,喜欢C/C++/Java/Python/Shell,同样喜欢前端Javascript,对基础知识非常地踏实,他在技术上没有限制自己的潜力,有什么就学什么。后来,我带他玩Docker/Go/K8S……分布式架构,他也上手的很快……像他这样的人,技术能力完全没得说,比我还大一岁,44岁了,还是一样的天天追代码细节,看Youtube的各种大会,翻github里的各种issue和pull request……

我同学这人,拥有了成为一个技术牛人几乎所有的条件:基础知识过硬,细节扎得深,面很广,学习能力强,有英文能力,逻辑思维能力不错,非常的自律,执行力也很强,抓得住重点……然而,只有一个小问题,就是没有到大公司历练过,我三番五次叫他从昆明出来,但是最终他都呆在昆明这个城市没有出来,因为有所谓的家庭约束。然而,我身边还有好些人,把自己家从北京搬到上海,从上海搬到深圳,从厦门搬到深圳……这样的人大有人在……像他这样的能力,在哪个公司都会是主力和骨干,对于一个公司的主力和骨干来说,家庭上的这些问题都是小问题都是有很多解的……

另外,我这个同学还是一个比较悲观的人,任何事情都是先想到不好的事,他关注负面的东西会胜于正面的东西,而且他还有一定的社交恐惧,怕与人相处和交流,时间越长越害怕,甚至有时候直接跟我说,“我就是不想改变”这样的话……其实,我以前也是一个很害怕与人交流的人,面试的时候,我根本不敢正眼看面试官一眼,也不知道与人怎么交流。但是,我与他不一样,我努力克服,不断地面试,与人面对面的交流,到一线技术客服接用户的电话,在公司里做分享,慢慢地到外面分享……3-5年就完全克服掉了。

其实,很多事情,完全是有解的,也没有必要担心,自己的心理障碍也是可以克服的,重点就是自己愿不愿意,只要愿意完成了一半,接下来就是不断的摸爬滚打坚持了。

  • 不限制自己的人,会穷举各种方法来解决问题,限制自己的人,只会找各式各样的问题或借口。
  • 不限制自己的人,会努力改变自己的问题和缺陷,限制自己的人,会放任自己。

另外几个故事

我还有另外几个故事(活到四十多,能看到好多人十几年的发展过程,感觉有点上帝视角了)

我还有一个以前团队里的一个小伙,人是很聪明,但就完全就是野路子,他对技术没有什么偏好,一个PHP程序员,做那个Discuz!论坛,公司被并购了,转成Java,开始研究Java的各种细节,对技术从来没有什么偏见,有什么就玩什么,每做一个项目,就算是一样的他都要用新的技术做一遍,然后跟着我做云计算,我教他TCP,教他C/C++,后来一起玩Docker/Go,等等,反正是一点就通,他是我见过学习能力最强的人。但是,有一个事他一直与我的想法不一样,就是我希望他先把软件设计好,再写代码,他非常不能理解,他习惯于直接动手开干,然后有什么问题就整什么问题,我也很难教育他。

有一天,他电话面了一下Facebook,电话面了15分钟后对方就放弃了,他受到了严重的打击。然后,他就开始找菲利宾人练英文口语了,我也让他做算法题,然后,他才发现,一道连算法都不是的纯编程题都提交几次都过不了,等他做完了Leetcode最初的那151道题后,整个人都改变了,写代码前认认真真地在纸上把程序的状态,处理时序以及可能遇到的一些条件先罗列出来,然后,进行逻辑设计后,再写,从此,他就开启他更大的天地了。我后来把他推荐给了微软,先在中国的Bing,在中国升好2-3级,然后去了美国的Azure,现在听说他准备要跟 k8s 的 co-founder Brendan Burns 混了(虽然,他现在还在印度人手下,但是,我真的不知道他未来能玩多大,因为今年他才33岁,而且非常聪明)

他以前是把自己封闭起来的,我叫他出来,他也不出来,后来因为一些办公室政治的原因不得不来找我,于是我就带着他玩了两年,跟他讲了很多外面的世界是怎么玩的,他这个人也是一个相当不善于社交的人,但是心是开放的,愿意接受新的东西,虽然对技术也有一定偏见,比如不喜欢Windows,但是也不会不喜欢到完全封闭。后来我跟他说,微软的技术相当的强的,你看到的技术只是表面,深层次的东西都是相通的,直到他到了微软后发现各种牛逼的东西,对微软系统的技术的态度也有了改变,而且我让他跟我说很多微软那边的事,我发现,他对技术了解的维度已经是越来越高级的了……

还是我以前团队的一个小伙,他是一个前端,他说前端的东西没什么意思,想来找我做后端,我也一点点带他……后来,我说,你如果想要玩得好,你必需来北京,无论现在你觉得过得有多好,你都要放弃掉,然后,尽最大可能出去经历一下世界最顶尖的公司,我甚至跟他说,如果他女朋友不跟来的话,就先分开一段时间,先自己立业,他来北京的时候,他之前的同事都等着看他的笑话,我说,那些人连想都不敢想,不必管他们。于是,他去了Amazon,再过了一年去了西雅图,我跟他说,接下来就是去AWS,然后,如果有足够的野心,用自己的年轻这个资本去硅谷创业公司赌一把……未来他怎么样我不知道,但至少他没有限制自己,他的未来不会有封顶……

也是我的同学,我跟他在大学是上下铺,后来他去了人民大学读计算机博士,大学的时候做国产数据库kingbase,然后去了一家外企,天天被派到用户那边做数据分析,后来,他想回科研单位做国产数据库,我说,别啊,你的技术比我好太多,还有博士理论加持,你不去国外顶尖公司玩玩,你不知道自己有多强的,于是他跟公司申请去了国外做核心,后来因为Hadoop的原因,公司的产品最终成为了历史,于是我说,你来了美国么,你一定要去AWS,于是他就去了AWS的Aurora团队,成为了AWS明星级产品的中坚力量,天天在改MySQL的核心源码,干了两年,正在晋升 Principal Software Engineer ……

这里我到不是说出国有多牛,也许你只关注能挣多少钱,但是我想说,他们之所以能有这样的际遇,除了他们本来就有实力,还更因为他们从来不给自己设制什么限制,就是那种“艺多不压身”,有什么就学什么,有更高的就去向更高的迈进,其它的像家庭什么的问题其实都是会有解的,真的不必担心太多……

别限制了自己

上面的这些故事,也许你能看得懂,也许你看得不一定能懂,这里,让我来做个总结吧

  • 做有价值的事。这个世界对计算机人才的要求是供不应求的,所以,不要让自己为自己找各式各样的借口,让自己活在“玩玩具”、“搬砖”和“使蛮力加班”的境地。其实,我发现这世界上有能力的人并不少,但是有品味的人的确很少。所谓的有价值,就是,别人愿付高价的,高技术门槛的,有创造力的,有颠覆性的……
  • 扩大自己的眼界,开放自己的内心。人要变得开放,千万不要做一个狭隘的民族主义者,做一个开放的人,把目光放在全人类这个维度,不断地把自己融入到世界上,而不是把自己封闭起来,这里,你的英文语言能力对你能不能融入世界是起决定性的作用。开放自己的心态,正视自己的缺点,你才可能往前迈进。你的视野决定了你的知不知道要去哪,你的开放决定了你想不想去
  • 站在更高的维度。面的维度会超过点的维点,空间的维度会超过面的维度,在更高维度上思考和学习,你会获得更多。整天在焦虑那些低维度的事(比如自己的薪水、工作的地点、稳不稳定、有没有户口……),只会让你变得越来越平庸,只要你站在更高的维度(比如: 眼界有没有扩大、可能性是不是更多、竞争力是不是更强、能不能解决更大更难的问题、能创造多大的价值……),时间会让你明白那些低维度的东西全都不是事儿。技术学习上也一样,站在学习编程语法特性的维度和站在学习编程范式、设计模式的维度是两种完全不一样的学习方式。
  • 精于计算得失。很多人其实不是很懂计算。绝大多数人都是在算计自己会失去多少,而不会算会得到多少。而一般的人也总是在算短期内会失去什么,优秀则总是会算我投入后未来会有什么样的回报,前者在算计今天,目光短浅,而后者则是舍在今天,得在明天,计算的是未来。精于计算得失的,就懂得什么是投资,不懂的只会投机。对于赚钱,你可以投机,但是对于自己最好还是投资。
  • 勇于跳出传统的束缚。有时候,跳出传统并不是一件很容易的事,因为大多数人都会对未知有恐惧的心理。比如:我看到很多人才都被大公司垄断了,其实,有能力的人都不需要加入大公司,有能力的人是少数,这些少数的人应该是所有的公司share着用的,这样一来,对于所有的人都是利益最大化的。这样的事现在也有,比如:律师、设计师……。但是,绝大多数有能力的技术人员是不敢走出这步。我在2015年到2016年实践过一年半,有过这些实践,做“鸡”的比“二奶”好多了,收入也好很多很多(不好意思开车了)……

庄子说过几句话——

井蛙不可以语于海者,拘于虚也;//空间局限

夏虫不可以语于冰者,笃于时也;//时间局限

曲士不可以语于道者,束于教也。//认识局限

别自己墙了自己,人最可悲的就是自己限制自己,想都不敢想,共勉!

————————————————————

注:这篇文章就是要劝大家更为开放,让自己有更多的可能性,能到更高的层次,做更有价值的事,成为更强更好的人……当然,如果你觉得你只想做一个平凡人,也和本文并不冲突……另外你也不要觉得这篇文章是让你要成为一个精英,但你一定要去摸高……这篇文章是告诉你一种面对人生的思考方式,在这种思考方式下,你会有更多的可能性,更大的场景……而不是直接把自己归到“平常人”,把自己“墙”了!

注:我以为用Java适合做架构这事应该是常识了,但是评论中有很多人非常反对这个事。那我解释一下吧:首先,小型的项目用什么语言都行,爱用什么用什么。但是,真正的企业级架构就不一样了,其中并不仅仅只是RESTful API或RPC,还有各种配套设施和控制系统,比如:应用网关,服务发现、配置中心、健康检查、服务监控、服务治理(熔断、限流、幂等、重试、隔离、事务补偿)、Tracing监控、SOA/ESB、CQRS、EDA……这些东西在非Java的技术栈体系内,很难看到全貌,Java强大的生态环境,就是让你把注意力放到更高层次的架构和业务上来的。(千万不要觉得,整几个服务RPC一下,加个缓存,加个队列,就能叫架构,那只是系统集成罢了)

(全文完)

我很无聊,该怎么办

如果你无聊,那是因为你什么都没做。

作者:Ibrahim Diallo

原文地址:https://idiallo.com/blog/im-bored-what-do-i-do

阅读本文大约需要 5 分钟

翻译:高行行

小结:

  1. 你消费得越多,就需要消费更多。一旦停止消费,你就会感到无聊。
  2. 解决无聊的方法并不是持续不断的娱乐。而是创造以前没有的东西。
  3. 生产胜于消费

翻译水平有限,如果有翻译不准的地方,敬请谅解

我在手机的滚动内容上浪费了很多时间。每秒都有更多的内容要消费。比如一个有趣的视频,一个段子,一个政治言论,一段鼓舞人心的引用,一个有趣的视频,一个段子,一个政治言论,一段鼓舞人心的引用,并且循环不断。我时不时地打破循环,转向一篇长篇且有趣的文章。我阅读并且感觉自己更聪明了。然后,我希望再找一篇文章,让我了解到更多相同的内容,但我却找不到更多。

“换句话说,我很无聊。”

我消费的越多,我需要消费的也越多,我也会感到越无聊。我经常转向电子游戏来释放压力。我可以花两个小时来射击虚拟物体,直到我开始觉得娱乐感不足。然后,我发现自己将手机拉近,可以在玩游戏的同时消费更多的滚动内容。只有同时激发我的全部感觉,我才会感觉到安心。

有些人说养成习惯需要 21 天,而另一些人则认为大约需要 66 天。无论哪种方式,它都表明我们是习惯的创造者,如果我们执行一项任务的时间足够长,它将成为我们日常的一部分。无聊成为了我们日常的一部分。我们必须消费社交媒体的内容来减少无聊,但消费越多,我们就越无聊。

这将成为新的常态。消费少了就会导致那种无聊的感觉。与朋友交谈,你会觉得无聊。他们不可能同时与电子游戏,政治言论和有趣的视频竞争。在谈话过程中,你会听到手机传来熟悉的嘟嘟声,你必须将其拿起。不是你忽视朋友或晚餐谈话,而是需要让他们都同时出现以使自己感觉正常。

我发现自己处于无聊习惯成型的早期阶段,因此我试图在此博客上写一篇文章。我不得不逼自己打出从我空荡荡的脑袋中冒出来的任何东西。我没有什么东西可写是一个事实。但是用这种方法发生了一些事。

消费生产的转变开始打破我过去养成的习惯所带来的厚重障碍。我写的越多,就越容易使我的想法浮出水面。我脑子里涌出的想法越多,我对娱乐的需求就越少。我整整一天的时间都在写一些我认为很有趣的东西,即使只是为了我自己

“生产胜于消费。”

心灵就像一顶神奇的兔子帽。你可以在魔术帽中装满无数只兔子,而且总还是有空间容纳另一只兔子。你不会看够了 Netflix 的节目,因为总是有再多的空间。如果你因为无聊而观看了一个节目,那么你可能会再观看 3 个节目。

生产也一样,总有额外可以挖掘的地方。你可以从帽子中拉出无数只兔子,当它看上去空了时,深入挖掘,你会发现另一只兔子。你生产的越多,你得到的想法就越多。而且附加的好处是你感到娱乐的需求减少了。

用通俗的话来说,就是制作一些东西、创造一些东西、构建一些东西。无论是什么

它可以是陶罐、纸上绘画、JavaScript 文件、木材构件、鞋架、沙堡、火柴制作的玩具房子、故事。只要你可以保存自己创造的内容并对其吹嘘,它就可以是任何东西。它甚至不必是新鲜玩意或优秀的。

解决无聊的方法并不是持续不断的娱乐。而是创造以前没有的东西

  • Copyrights © 2015-2023 高行行
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信