elasticsearch match查询

es中的查询请求有两种方式,一种是简易版的查询,另外一种是使用JSON完整的请求体,叫做结构化查询(DSL)。
由于DSL查询更为直观也更为简易,所以大都使用这种方式。
DSL查询是POST过去一个json,由于post的请求是json格式的,所以存在很多灵活性,也有很多形式。
这里有一个地方注意的是官方文档里面给的例子的json结构只是一部分,并不是可以直接黏贴复制进去使用的。一般要在外面加个query为key的机构。

match

最简单的一个match例子:

查询和"哺乳期长湿疹怎么办"这个查询语句匹配的文档。

{
  "query": {
    "match": {
        "content" : {
            "query" : "哺乳期长湿疹怎么办"
        }
    }
  }
}

上面的查询匹配就会进行分词,比如"哺乳期长湿疹怎么办"会被分词为"哺乳期、哺乳、乳期、期长、湿疹、怎么办、怎么、办", 所有包含这些分词中的一个或多个的文档就会被搜索出来。
并且根据lucene的评分机制(TF/IDF)来进行评分。

match_phrase

比如上面一个例子,一个文档"哺乳期长湿疹怎么办"也会被搜索出来,那么想要精确匹配所有同时包含这些分词的文档怎么做?就要使用 match_phrase 了

{
  "query": {
    "match_phrase": {
        "content" : {
            "query" : "哺乳期长湿疹怎么办"
        }
    }
  }
}

完全匹配可能比较严,我们会希望有个可调节因子,少匹配一个也满足,那就需要使用到slop。

{
  "query": {
    "match_phrase": {
        "content" : {
            "query" : "哺乳期长湿疹怎么办",
            "slop" : 1
        }
    }
  }
}

multi_match

如果我们希望两个字段进行匹配,其中一个字段有这个文档就满足的话,使用multi_match

{
  "query": {
    "multi_match": {
        "query" : "哺乳期长湿疹怎么办",
        "fields" : ["title", "introduction"]
    }
  }
}

但是multi_match就涉及到匹配评分的问题了。

我们希望完全匹配的文档占的评分比较高,则需要使用best_fields

{
  "query": {
    "multi_match": {
      "query": "哺乳期长湿疹怎么办",
      "type": "best_fields",
      "fields": [
        "tag",
        "introduction"
      ],
      "tie_breaker": 0.3
    }
  }
}

意思就是完全匹配"宝马 发动机"的文档评分会比较靠前,如果只匹配宝马的文档评分乘以0.3的系数

我们希望越多字段匹配的文档评分越高,就要使用most_fields

{
  "query": {
    "multi_match": {
      "query": "哺乳期长湿疹怎么办",
      "type": "most_fields",
      "fields": [
        "tag",
        "introduction"
      ]
    }
  }
}

我们会希望这个词条的分词词汇是分配到不同字段中的,那么就使用cross_fields

{
  "query": {
    "multi_match": {
      "query": "哺乳期长湿疹怎么办",
      "type": "cross_fields",
      "fields": [
        "tag",
        "introduction"
      ]
    }
  }
}

每一天都需要坚持长期主义

原文:https://mp.weixin.qq.com/s?__biz=MzA5NjM0Nzc3NA==&mid=2650451948&idx=1&sn=102f6bee1ddf0eb5b4f53bdd23ab5da9&chksm=88bf7cfdbfc8f5ebd78ff15aaeb36e69de93002ebe4fb0589918f01e47e12fc9d2307a469e90&scene=132#wechat_redirect

最近在看杰夫 · 贝佐斯的《长期主义》一书,这本书大家争议比较多的原因在于它很简单,没有什么「料」,全书分为两部分:第一部分是贝佐斯历年来致股东的信,第二部分是贝佐斯若干年的访谈摘录。

这本书看完之后最大的感受是「平淡无奇」,因为贝佐斯反复强调的就是长期主义、顾客优先等理念,书中的案例和故事也都是围绕这些理念展开。

而书中给我留下最深印象的是「放眼三年后」一节,其中讲述的居然是贝佐斯的睡眠习惯。

贝佐斯认为,今天Amazon所取得的任何成绩,都源于3年前的决策,而非当下的努力。所以他很在意决策的质量, 他认为高级管理者最重要的职责是「对少数重大问题做出决策,而不是每天对于成百上千件小事做决定」。「如果今天能做出三个好的决策,那就足够了,而在这三个决策的质量上,我则要尽心尽力做好」。在「少而关键的决策」上,贝佐斯佩服的人是巴菲特,因为巴菲特强调:「如果一年能做出三个好决策,那他就没有后顾之忧了。」

为了保证决策的质量,就得保证睡眠的质量。所以贝佐斯每天的日程安排有一个基本原则:「睡眠优先」,他会起得很早,悠闲地放空。他坦言「悠闲的时间对我而言非常重要」,所以他会很早起床,放空自己,而第一场会议一般安排到早晨10点,任何考验脑力的事情要放在早晨10点的会议精心讨论。而最后一个会议都会在下午5点前结束,因为他此时已经没有任何脑力讨论问题。

贝佐斯不仅自己这样做,而且要求自己的高级主管也这样做。因为只有这样做,才是「扎根于未来而工作,也扎根于未来而生活」。贝佐斯要求,任何直接汇报给他的人,都不应该专注于当下季度。看到这里,我们每个人都可以反思一下自己的睡眠和开会习惯。

这件事给我的启发如下:

1、 管理者必须坚持「长期主义」

今天的结果是三年前的决策所致,所以高级管理者要把更多的精力用来做对三年后有价值的决策。其实任何层面的管理者的主要职责,都是对未来做决策,只不过决策影响的周期和范围不同而已。只要是管理者,都应该在意决策的质量,而非数量。

但我们看到,在高速发展的业务中,很多管理者,尤其是高级管理者忙到没时间复盘和思考——这是最勤奋,也最具迷惑性的自杀行为。短期体现不出来,长期的影响非常明显。事实上,几乎所有公司都很忙碌,但只有少数公司能成功。为什么大多数公司既忙碌,又不成功,核心原因一定包含「管理者没有时间复盘和思考」这一条。

为了能持续在少而关键的事情上做出高质量的决策,管理者一定要保证充足的睡眠,因为只有睡眠好、精力好,才能确保每天做出三个正确的决策。从长期看,每天能做三个正确的决策,收益巨大。任何影响睡眠的习惯都是「短期主义」的表现。

创业公司的管理者难免忙碌,但一定要找到适当的空闲,因为忙碌之后的空闲是灵感的温床,是复盘发生的场所,是认知提升的机会。管理者的认知提升是公司和团队的最大福音,这意味着我们可以花更少的代价,得到更好的结果。

2、个人也要坚持「长期主义」

我们是自己这家「人生有限公司」的高级管理者,我们的人生主要取决于自己多年前决策的质量,比如与谁结婚、去哪家公司、进入哪个行业、投资哪家公司的股票等等。这些决策之于个人的重要性,一点也不亚于高级管理者在公司所做出的经营决策。

所以,如何能在日常生活中坚持「长期主义」,就会构成人与人之间的分水岭。

3、我们可以在每一天、每件事上都坚持「长期主义」

虽然长期主义的影响主要体现在一些关键要事的决策上,但为了做到这一点,我们需要在日常的生活和工作中,在每一天和每件事上都坚持「长期主义」。

比如,在知识积累方面,其实我们每天都在写Memo(备忘录),比如你给朋友发的微信,你给同事发的飞书消息。如果你在意价值、在意沉淀,在发这些消息的时候就会关注它的质量,也就是关注它的长期价值。这样的消息就是Memo,记录下来,持续复盘、深化,就是认知的提升。事实上,正是因为理解了这一点,我才会养成每天把自己在各种IM软件上的关键思考沉淀到flomo中的习惯。

此外,每天健康饮食、坚持运动,有充足的睡眠等等,都是坚持「长期主义」的表现,因为我们把每天这些看似微小的举动与长期价值关联在一起。并且,这些习惯也会非常有助于我们每天做出高质量的决策。

4、我们需要从今天开始就切换到「长期主义」

从短期主义切换到长期主义并不需要很长的准备时间。你一直在寻找的答案就在每一天,每一件事上面。只要我们肯改变,那么每一天、每件事都是契机。立刻改变当下做事的方式,立刻改变度过今天的方式,可能没有立刻的影响和回报,但改变已经在悄然发生。其实,一直以来最困扰我们的事情,答案往往只能在今天,只能在当下这件事上。

很多人表面上赞同「长期主义」这四个字,但是落到具体行动上,他会说「我今天很忙,哪里来的时间去休息,更没有时间思考和学习。等以后闲下来再说」。但对于一个习惯忙碌的人而言,哪里会有空闲的时间?

所以,我们只有两种命运:一种是持续陷于忙碌不可自拔;另一种是在今天、在当下,在这件事上就做出改变。我们是自己命运大船的船长,除非我们自己愿意立刻改变航向,不会有任何外力改变我们的命运。

我们可以今天就分析一下自己最近每天的时间投入,看看有多少是在为未来投资,有多少是当下应急。一个明智的船长,应该有更多的时间为未来投资,因为在正确的方向上努力是最重要的事情,我们要有足够的精力思考和判断何谓正确的方向。

《长期主义》一书的精华就是「长期主义」四个字,如何从Day ONE就坚持长期主义,如何在每一天坚持「长期主义」,如何在每件事上坚持「长期主义」。人和人、公司与公司之间的差别,就是这样一天天、一件件地累积而成。

最后再次强调一下:

身处当今社会,有三点只要注意到,日子就不会差(而且会越过越好),这三点分别是:回归常识,坚持自我,着眼长期。

第一、信息泛滥但常识缺失,回归常识就有超额收益;

第二、大众流行但自我缺失,只要能探索自己,坚持自己就会被最终认可;

第三、速成备受瞩目,但长期耐心不足,只要能坚持长期主义,就一定能超越竞争。

重要的东西用眼睛是看不见的

Metadata

Highlights

  • 驯化是创造关系,是关系双方建立联系,是彼此需要,是产生羁绊,是彼此的唯一。 (View Highlight)
  • 爱情,便是如此。我们建立情感的联系,从此,有了牵挂,有了羁绊,在这人世间,我们将会是彼此的挂念和唯一。 (View Highlight)
  • 我将能够辨别一种与众不同的脚步声。别人的脚步声会让我躲到地下,而你的脚步声就像音乐般美好,会让我走出洞穴。 (View Highlight)
  • 正是你为你的玫瑰付出的时间,使得你的玫瑰是如此的重要。 (View Highlight)
  • 重要的东西用眼睛是看不见的,只有用心才能看得清楚。 (View Highlight)
  • 因为,真正的爱不是忘乎所以,是深思熟虑,是奉献身心的重大决定。 (View Highlight)
  • 我不愿你为了我放弃你的热爱,我希望我对你的爱,让你变成更好的人。 (View Highlight)
  • 爱情本自有它的发展规律,由远及近,由陌生到熟悉,由相识到相知。隔着遥远的距离,在包容和理解中相互一点点接近。 (View Highlight)
  • 真正的爱是源于激情褪去的自主选择,需要依靠实际行动来证明,心甘情愿地为爱投入和奉献,并坚持履行对爱的承诺。 (View Highlight)
  • 爱需要仪式,仪式是使某一天、某一时刻变得非同一般的东西。 (View Highlight)
  • 爱一个东西就要为她负责,被爱的时候你也是自由的。 (View Highlight)
  • 爱是,我想到你的时候,你是你,风吹麦浪是你,忽远忽近的脚步声是你,星星眨眼也是你。 (View Highlight)
  • 就像《蔷薇岛屿》说的,最好的爱情是两个人彼此相伴,不要束缚,不要索取,不要纠缠,不要占有。不要渴望从对方身上挖掘意义,那是注定要落空的东西。 (View Highlight)

如何计算两个字符串之间的文本相似度

前言

平时的编码中,我们经常需要判断两个文本的相似性,不管是用来做文本纠错或者去重等等,那么我们应该以什么维度来判断相似性呢?这些算法又怎么实现呢?这篇文章对常见的计算方式做一个记录。

Jaccard 相似度

首先是 Jaccard 相似度系数,下面是它在维基百科上的一个定义及计算公式。

The Jaccard index, also known as Intersection over Union and the Jaccard similarity coefficient (originally given the French name coefficient de communauté by Paul Jaccard), is a statistic used for gauging the similarity and diversity of sample sets. The Jaccard coefficient measures similarity between finite sample sets, and is defined as the size of the intersection divided by the size of the union of the sample sets:

其实总结就是一句话:集合的交集与集合的并集的比例.

java 代码实现如下:

    public static float jaccard(String a, String b) {
        if (a == null && b == null) {
            return 1f;
        }
        // 都为空相似度为 1
        if (a == null || b == null) {
            return 0f;
        }
        Set<Integer> aChar = a.chars().boxed().collect(Collectors.toSet());
        Set<Integer> bChar = b.chars().boxed().collect(Collectors.toSet());
        // 交集数量
        int intersection = SetUtils.intersection(aChar, bChar).size();
        if (intersection == 0) return 0;
        // 并集数量
        int union = SetUtils.union(aChar, bChar).size();
        return ((float) intersection) / (float)union;
    }

Sorensen Dice 相似度系数

与 Jaccard 类似,Dice 系数也是一种计算简单集合之间相似度的一种计算方式。与 Jaccard 不同的是,计算方式略有不同。下面是它的定义。

The Sørensen–Dice coefficient (see below for other names) is a statistic used to gauge the similarity of two samples. It was independently developed by the botanists Thorvald Sørensen[1] and Lee Raymond Dice,[2] who published in 1948 and 1945 respectively.

需要注意的是,他是:集合交集的 2 倍除以两个集合相加。并不是并集.

java 代码实现如下:

    public static float SorensenDice(String a, String b) {
        if (a == null && b == null) {
            return 1f;
        }
        if (a == null || b == null) {
            return 0F;
        }
        Set<Integer> aChars = a.chars().boxed().collect(Collectors.toSet());
        Set<Integer> bChars = b.chars().boxed().collect(Collectors.toSet());
        // 求交集数量
        int intersect = SetUtils.intersection(aChars, bChars).size();
        if (intersect == 0) {
            return 0F;
        }
        // 全集,两个集合直接加起来
        int aSize = aChars.size();
        int bSize = bChars.size();
        return (2 * (float) intersect) / ((float) (aSize + bSize));
    }

Levenshtein

莱文斯坦距离,又称 Levenshtein 距离,是编辑距离的一种。指两个字串之间,由一个转成另一个所需的最少编辑操作次数。

简单的说,就是用编辑距离表示字符串相似度, 编辑距离越小,字符串越相似。

java 实现代码如下:

    public static float Levenshtein(String a, String b) {
        if (a == null && b == null) {
            return 1f;
        }
        if (a == null || b == null) {
            return 0F;
        }
        int editDistance = editDis(a, b);
        return 1 - ((float) editDistance / Math.max(a.length(), b.length()));
    }

    private static int editDis(String a, String b) {

        int aLen = a.length();
        int bLen = b.length();

        if (aLen == 0) return aLen;
        if (bLen == 0) return bLen;

        int[][] v = new int[aLen + 1][bLen + 1];
        for (int i = 0; i <= aLen; ++i) {
            for (int j = 0; j <= bLen; ++j) {
                if (i == 0) {
                    v[i][j] = j;
                } else if (j == 0) {
                    v[i][j] = i;
                } else if (a.charAt(i - 1) == b.charAt(j - 1)) {
                    v[i][j] = v[i - 1][j - 1];
                } else {
                    v[i][j] = 1 + Math.min(v[i - 1][j - 1], Math.min(v[i][j - 1], v[i - 1][j]));
                }
            }
        }
        return v[aLen][bLen];
    }

代码中的编辑距离求解使用了经典的动态规划求解法。

我们使用了** 1 - ( 编辑距离 / 两个字符串的最大长度) ** 来表示相似度,这样可以得到符合我们语义的相似度。

汉明距离

汉明距离是编辑距离中的一个特殊情况,仅用来计算两个等长字符串中不一致的字符个数。

因此汉明距离不用考虑添加及删除,只需要对比不同即可,所以实现比较简单。

我们可以用similarity=汉明距离/长度来表示两个字符串的相似度。

java 代码如下:

    public static float hamming(String a, String b) {
        if (a == null || b == null) {
            return 0f;
        }
        if (a.length() != b.length()) {
            return 0f;
        }

        int disCount = 0;
        for (int i = 0; i < a.length(); i++) {
            if (a.charAt(i) != b.charAt(i)) {
                disCount++;
            }
        }
        return (float) disCount / (float) a.length();
    }

下面是测试用例:

        Assert.assertEquals(0.0f, StringSimilarity.hamming("java 开发", "大过年的干啥"), 0f);
        Assert.assertEquals(0.6666667f, StringSimilarity.hamming("大过年的吃肉", "大过年的干啥"), 0f);

余弦相似性

首先是余弦相似性的定义:

余弦相似性通过测量两个向量的夹角的余弦值来度量它们之间的相似性。0 度角的余弦值是 1,而其他任何角度的余弦值都不大于 1;并且其最小值是-1。从而两个向量之间的角度的余弦值确定两个向量是否大致指向相同的方向。两个向量有相同的指向时,余弦相似度的值为 1;两个向量夹角为 90°时,余弦相似度的值为 0;两个向量指向完全相反的方向时,余弦相似度的值为-1。这结果是与向量的长度无关的,仅仅与向量的指向方向相关。余弦相似度通常用于正空间,因此给出的值为 0 到 1 之间。

计算公式如下:

余弦我们都比较熟悉,那么是怎么用它来计算两个字符串之间的相似度呢?

首先我们将字符串向量化,之后就可以在一个平面空间中,求出他们向量之间夹角的余弦值即可。

字符串向量化怎么做呢?我举一个简单的例子:

A: 呼延十二
B: 呼延二十三

他们的并集 [呼,延,二,十,三]

向量就是并集中的每个字符在各自中出现的频率。
A 的向量:[1,1,1,1,0]
B 的向量:[1,1,1,1,1]

然后调用上面的公式计算即可。

java 代码实现如下:

    public static float cos(String a, String b) {
        if (a == null || b == null) {
            return 0F;
        }
        Set<Integer> aChar = a.chars().boxed().collect(Collectors.toSet());
        Set<Integer> bChar = b.chars().boxed().collect(Collectors.toSet());

        // 统计字频
        Map<Integer, Integer> aMap = new HashMap<>();
        Map<Integer, Integer> bMap = new HashMap<>();
        for (Integer a1 : aChar) {
            aMap.put(a1, aMap.getOrDefault(a1, 0) + 1);
        }
        for (Integer b1 : bChar) {
            bMap.put(b1, bMap.getOrDefault(b1, 0) + 1);
        }

        // 向量化
        Set<Integer> union = SetUtils.union(aChar, bChar);
        int[] aVec = new int[union.size()];
        int[] bVec = new int[union.size()];
        List<Integer> collect = new ArrayList<>(union);
        for (int i = 0; i < collect.size(); i++) {
            aVec[i] = aMap.getOrDefault(collect.get(i), 0);
            bVec[i] = bMap.getOrDefault(collect.get(i), 0);
        }

        // 分别计算三个参数
        int p1 = 0;
        for (int i = 0; i < aVec.length; i++) {
            p1 += (aVec[i] * bVec[i]);
        }

        float p2 = 0f;
        for (int i : aVec) {
            p2 += (i * i);
        }
        p2 = (float) Math.sqrt(p2);

        float p3 = 0f;
        for (int i : bVec) {
            p3 += (i * i);
        }
        p3 = (float) Math.sqrt(p3);

        return ((float) p1) / (p2 * p3);
    }

对上面的代码运行了测试用例,可以看到基本符合我们的期望。

        Assert.assertEquals(0.70710677f, StringSimilarity.cos("apple", "app"), 0f);
        Assert.assertEquals(0.8944272f, StringSimilarity.cos("呼延十二", "呼延二十三"), 0f);
        Assert.assertEquals(0.0f, StringSimilarity.cos("数据工程", "日本旅游"), 0f);

总结

本文简单的介绍了几种不同的计算纯文本之间相似度的方式,他们在一定程度上都是奏效的,但是,各自也有各自的一些含义在里面,比如有的使用编辑距离来描述,有的用向量夹角来描述。所以在使用到本文中的方式时,还是要多多了解他的原理,结合自己的业务实际,选择其中的一种或者几种进行使用。

作者:呼延十
原文链接:https://juejin.im/post/5dca66e0e51d456a2e6556f8

如何设计一个高性能 Elasticsearch mapping

前言

在关系型数据库设计当中,表的设计尤其重要,然而关系型数据库更关注的表与表之间的关系,以及表的划分是否合理,而 Elasticsearch 中却更加关注字段类型的设计,一个好的字段类型设计可以更好的利用 Elasticsearch 的搜索分析特性。

mapping

如果说我们想要用好 Elasticsearch,那么就必须要先了解 mapping 什么是 mapping。一句话:mapping是定义如何存储和索引文档及其包含的字段的过程。

mapping 能做什么

前面我们提到,在 Elasticsearch 中,mapping 类似于传统关系型数据库的表结构定义,主要做以下几件事:

  • 定义字段名称和字段类型。
  • 定义倒排索引相关的配置,比如是否被索引,是否可以被分词等。

mapping 可以分为两种:Dynamic mapping 和 Explicit mapping

Dynamic mapping

Dynamic mapping 即:动态映射。动态映射顾名思义就是 mapping 会被动态创建,也就是说我们不需要定义 mapping 就可以往一个索引插入数据,插入索引数据之后,Elasticsearch 会根据插入的数据自动推测数据类型,进而动创建 mapping

比如下面就是往一个不存在的索引 index_001 插入一条数据:

PUT index_001/_doc/1
{
  "name":"lonely wolf",
  "age": 18,
  "create_date":"2021-05-19 20:45:11",
  "update_date":"2021-05-23"
}

插入数据之后,执行 GET index_001 来查询一下索引信息:

可以发现,这时候索引已经被自动创建了,而且 age 字段被 Elasticsearch 定义为 long 类型,update_date 被定义为 data 类型,其他两个字段则被推测为 text 类型。

Elasticsearch 中自动映射类型规则可以通过 dynamic 参数进行配置,dynamic 类型有 4 种:

dynamic=true

默认值。当设置为 true 时,一旦有新字段插入文档,则 mapping 会被同步更新。

我们在上面的文档中再插入一个新文档,新文档新增一个 address 字段:

PUT index_001/_doc/2
{
  "name":"lonely wolf2",
  "age": 20,
  "create_date":"2021-05-23 11:37:11",
  "update_date":"2021-05-23",
  "address":"广东深圳"
}

然后再查看一下 mapping,可以看到 mapping 已经新增了一个 address 字段,mapping 字段被更新意味着该字段会加入索引:

dynamic=runtime

这个类型和 true 类型非常相似,但是有一个非常大的区别就是,虽然加入新字段也会更新 mapping,但是新加入的字段不会被索引,也就是不会使得索引变大,不过虽然不被索引,但是新加入的字段依然可以被查询,只是查询的代价会更大。所以这种类型一般不建议用在经常查询的条件字段上,而更适合用在一些不确定数据结构的日志类索引中。

修改 dynamic 类型:

PUT index_001/_mapping
{
  "dynamic":  "runtime"
}

新增一个文档,并加入一个新字段:

PUT index_001/_doc/3
{
  "email":"123@qq.com"
}

最后询一下 mapping,可以看到字段属性是 runtime,而且类型是 keyword

下表就是自动创建 mapping 时,Elasticsearch 的映射关系:

dynamic=false

当设置为 false 时,新加入的字段不会被更新到 mapping,也就是说新字段不会被索引,故以这个字段为条件进行搜索时,无法被搜索到(这一点要注意和 runtime 类型进行区分),不过虽然无法被索引,但是该字段会出现在 _source 中。也就是说该字段不能作为查询条件,但是能被查询出来

接下来我们将 dynamic 修改为 false,并新增一个字段来验证,可以发现新增的字段会出现在 _source 中,但是无法作为条件被查询出来:

dynamic=strict

这种类型最为严格,表示不允许新增一个不在 mapping 中的字段,一旦新增的字段不在 mapping 定义中,则直接报错:

是否可以修改 mapping 中的数据类型

在 Elasticsearch 中,一旦一个字段被定义在了 mapping 中,是无法被修改的,因为一旦字段被修改了,就会无法被索引(新增字段除外),所以一般我们需要修改索引的话,都会重建索引,并采用 reindex 操作来迁移数据。

关闭 dynamic mapping

可以通过以下两个配置来关闭 dynamic mapping,以下两个属性默认值均为 true,如果需要关闭,则需要修改为 false

action.auto_create_index: true
index.mapper.dynamic: true

Explicit mapping

Explicit mapping 即:显式映射。也就是说这时候我们需要显示的定义字段类型。

Elasticsearch 中支持的字段类型很多,在这里就举一些比较常用的字段类型:

text 类型

这是最常用的一种类型,存储字符串,用于全文索引。当字段被定义为 text 类型时,默认不能用于聚合,排序等操作:

可以看到,用 text 类型字段排序汇报凑,如果想要允许这些操作,可以通过设置 fielddata=true,如下

PUT my-index-011/_mapping
{
  "properties": {
    "my_field": { 
      "type":     "text",
      "fielddata": true
    }
  }
}

field 字段存储在堆内存中,因为其涉及到的计算比较消耗性能,所以一般不建议设置 fielddata=true,而是通过建立一个 keyword 子域来实现(默认方式):

PUT index_111
{
  "mappings": {
    "properties": {
      "my_field": { 
        "type": "text",
        "fields": {
          "keyword": { 
            "type": "keyword"
          }
        }
      }
    }
  }
}

这种定义方式我们可以将一个字段同时作为 text 和 keyword 类型使用,如果要用于聚合或者排序等操作则可以使用 字段名.keyword 来作为字段名来进行操作:

keyword 类型

这种类型也非常常用,该字段存储的数据表示一个整体,不可被分词,所以一般不会用来定义大本文的全文检索字段,而是用来存储一些结构化的字符串,比如:id,邮箱,标签等。

keyword 类型一般用于聚合,排序等操作。除此之外,该字段还有两种衍生类型:constant_keyword 和 wildcard

  • constant_keyword:一般用于定义常量类型,比如一个索引中某一个字段全部为同一个值,可以定义为这种类型。
  • wildcard:一般用于模糊匹配查询或者正则匹配查询。

如下就是一个模糊匹配查询的示例(可以配合通配符使用,类似于关系型数据库的 like 操作):

GET index_112/_search
{
  "query": {
    "wildcard": {
      "my_wildcard": {
        "value": "*quite*lengthy"
      }
    }
  }
}

date 类型

用于定义日期类型,定义日期类型的同时,可以通过 format 来指定日期的格式:

PUT index_113
{
  "mappings": {
    "properties": {
      "date": {
        "type":   "date",
        "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
      }
    }
  }
}

numeric 类型

Elasticsearch 中提供了比较多的格式用来表示不同长度的数字类型:

定义方式如下所示:

PUT index_002
{
  "mappings": {
    "properties": {
      "number_of_bytes": {
        "type": "integer"
      },
      "time_in_seconds": {
        "type": "float"
      },
      "price": {
        "type": "scaled_float",
        "scaling_factor": 100
      }
    }
  }
}

boolean 类型

布尔类型比较简单,只有 true 和 false 两种:

PUT index_001
{
  "mappings": {
    "properties": {
      "is_published": {
        "type": "boolean"
      }
    }
  }
}

其他类型

除了上面介绍的一些比较常用的数据类型,Elasticsearch 中还有一些高级数据类型:如 Nested(嵌套类型),地理数据类型,ip 类型等。

总结

Elasticsearch 中支持动态 mapping 和显示 mapping 两种,在使用中有时候可以先插入一条数据到临时索引,等自动生成 mapping 之后,在对现有 mapping 进行修改调整,在字段上尤其要考虑好 text 类型和 keyword 类型的设置,如果需要支持全文搜索和分词搜索,则需要使用 text 类型,需要支持关键字模糊搜索或者聚合排序等操作可以考虑使用 keyword 字段。

​有一种修养,叫遇事不指责

Metadata

Highlights

  • 大道之行,不责于人 (View Highlight)
  • 人生中最难的,就是在遇事时不指责他人。 (View Highlight)
  • 不轻易指责他人,是一种修养 (View Highlight)
  • 学会闭嘴,不轻易指责他人,是做人最基本的修养。 (View Highlight)
  • 很多时候,我们看到的都不是真相,把自己的想法强加给他人,只会让语言成为手中的利剑。 (View Highlight)
  • 一个人最大的恶意,就是用“我认为”来肆意指责他人。 (View Highlight)
  • 如果不能感同身受,请闭嘴保持善良。 (View Highlight)
  • 遇事多赞美,少批评 (View Highlight)
  • 如今的他,在职场中善于发现同事的优点,不轻易指责他人,他也活成了别人心里的一道光。 (View Highlight)
  • “即使在最好最有爱的关系中,夸奖也是必不可少的。正如要使车轮转得更快,润滑剂是必不可少的。” (View Highlight)
  • 真正有格局的人,不会放任自己的情绪,因为他知道,恶言恶语会如同一把刀,插进别人的心里。 (View Highlight)
  • 静水流深,人贵谦逊。 (View Highlight)
  • 懂得欣赏别人的优点,适时夸赞他人,真心实意,赤诚以待,这是最好的处世之道 (View Highlight)
  • 如果你能在指责别人的时候,先反思自己,你就会明白每个人都有自己的难处。 (View Highlight)
  • “以责人之心责己,以恕己之心恕人”。 (View Highlight)
  • 一个聪明的人,一定懂得己所不欲,勿施于人,会多换位思考,少批评指责。 (View Highlight)

1个牛逼的思路

Metadata

Highlights

  • 不要听别人说什么,而是要看别人都主动去做了什么。
  • 因为每个人都必然是利己的,只不过有些人受制于眼界和认知的不足,导致他们无法看得更远,无法做出更加明智的决策,所以只能一直在重复着低效的努力。
  • 几乎每个人都会做「自利归因」,也就是把当下的成功,都归到自己身上,把当下的失败,都归到「运气」和「环境」这些事物之上。
  • 他们手中的牌,说句不好听的,最大的,可能只有对4了,而你手中的牌呢,最小的,还是对4,其他的,不是王炸,就是4条2。
  • 如果你不去做换位思考的话,遇到和你有着完全不一样消费习惯的人,你可能会对他们的行为,做「价值判断」。
  • 所以啊,多点做换位思考,多去了解别人,是在什么样的环境中,成长起来的,好好去了解,好好去倾听,你就能够破除「我执」,你就会变得更加从容和淡定,你的人缘,也会越来越好,而且,更重要的,你还有可能赚到越来越多的钱。

我们似乎被“幽灵社交”笼罩了

Metadata

Highlights

  • 爱的反面不是恨,而是冷漠 (View Highlight)
  • “幽灵社交”(英文原名:Ghosting,也被称为鬼影社交)的意思指的是,别人在没有任何解释的情况下,就切断了所有的联系,通俗说法叫“玩消失”。 (View Highlight)
  • 轻度等级:
    "与朋友争吵,朋友不再回短信",
    "或是朋友忘记回消息"。 (View Highlight)
  • 中度等级:
    “当你和这个人见过几次面,
    就陷入深深的回避。” (View Highlight)
  • 重度等级:
    "当你与一个人经过了一段时间的接触,建立了深度关系,
    对方却悄无声息地离开。" (View Highlight)
  • 玩消失的人用近乎逃避的方式,残忍地传达到了自己的意图,即便“被分手”的一方苦苦逼问或者尽力挽回,大部分情况下很难得到令自己满意的答复。 (View Highlight)
  • 社交媒体降低了我们在终结关系时需要付出的代价。 (View Highlight)
  • 一个人潇洒丢掉的,另一个人被迫去捡。 (View Highlight)
  • 无论是短暂玩消失还是永久退出对方的世界,突然中断的那一刻多少会带来不适的情绪。 (View Highlight)
  • 社交媒体的时代,让我们时刻向别人让渡控制权。 (View Highlight)
  • "当事情发生的时候,我感觉仿佛有人在我的肚子上打了一拳,这种漠视是一种侮辱。" (View Highlight)
  • 心理学家们早就提出:在人际交往活动中,我们的大脑进化出了一套社会监控系统,通过对周围环境的扫描来寻找线索,并积累一定的经验,这样我们就知道如何在社交场合做出反应,相应地调节自己的行为。 (View Highlight)
  • 你的选择机械地变成了是否回复信息、什么时候回复信息、回复什么内容。 (View Highlight)
  • 对生活的感觉,就是这样失控的。 (View Highlight)
  • “被虐之后”人们往往会给对方找补理由。
    大概是出了门手机没电?还是手机丢了?是不是一直在开会呀?还是开车不能看手机? (View Highlight)
  • 心理学界将幽灵式社交定义为“情感酷刑”(emotional cruelty),它有点像我们常说的冷战,但杀伤力往往比冷战更甚。
    被排斥的人压根没有机会讨论问题所在,也没有足够的信息来帮助消化这一痛苦的过程,搞不好还会出现人生三大错觉之一:“幽灵震动”(Phantom Vibration Syndrome)。 (View Highlight)
  • 心理学家詹妮斯·维尔豪尔(Jennice Vilhauer)认为:“玩失踪与一个人的自我舒适度,和他们如何处理自己的情绪有很大关系,很多人想要避开那些让他们不舒服的东西。” (View Highlight)
  • 那些悄无声息就失联的人,更专注于避免自己的情绪不适,与此同时,他们并不考虑这会给别人带来怎样的影响。 (View Highlight)
  • “在约会的社交世界里,人们会遇到很多自己生活社交圈以外的人,所以就会产生一种感觉,如果你甩了某人,也没有什么责任。” (View Highlight)
  • 当这种情况发生得越多,足够数量的轻松选择让我们的情感变得麻木,所以人们变得愈加不敏感。 (View Highlight)
  • "我认为这也是当代恋情如此吸引人的部分原因:因为你们没有共同的朋友,没有通过其他渠道认识,所以即便对方从地球上消失,也并不是世界末日。" (View Highlight)
  • “对命运有更强信念的人更有可能选择人间蒸发。和一个人在一起一段时间后,意识到对方大概不是命中注定,丧失了意义感,所以就决定不再联系。” (View Highlight)
  • 吉莉·弗里德曼博士(Gili Freedman)则在2018年的一篇论文中提到,“是否玩失联”与我们对未来的感觉有很大关系。
    这关乎人们是否认为自己的对象就是“命中注定的那个人”,这在某个程度上其实是一个信仰与命运的问题。 (View Highlight)
  • 认识到所有的社交都有保质期,直面自己的痛苦,大概是最难做到但也是最基础的步骤。
    不管是死党父母恋人,没有人能陪你走完全程。 (View Highlight)
  • 经历幽灵社交并不能说明你是否值得被爱,这只能说明,对方没有勇气去处理自己的情绪,也不敢面对你的情绪。 (View Highlight)

使用obsidian實現logseq移動端記錄

目前在使用obsidian记录间隙笔记的痛点之一是无法快速方便把链接到当前文件的笔记进行整合,只能逐一复制。在链接文件较多的情况下是一种灾难。logseq可以弥补这部分的缺失,支持直接将链接的笔记拖拽整合。

工作日的地铁上是我集中阅读的时间,我需要记录大量的文章摘抄和想法。虽然logseq已发布移动端,但只能基于icloud等云盘进行同步。介于icloud在win上拉胯的表现,实际一番折腾后,果断放弃之。刚好我有订阅obsidian的云同步服务,于是有了一个想法(这个方法网上也有人分享过),将logseq的库地址直接选obsidian,好处有3点:

  1. obsidian记录的markdown文件能直接在logseq中编辑显示
  2. 利用obsidian的同步功能实现logseq的同步
  3. 移动端的记录也能实时进行同步

obsidian移动端编辑功能还是不太让人满意的。例如要在手机上记录间隙笔记,要键入时间和标签,功能上能用,但是不好用,页面也不好看,记录的欲望直线下降。用过flomo的小伙伴都清楚,flomo的主要目的是帮助你「记录想法的川流」,让用户能尽量多的无压力的记录下来自己的想法,整体的输入感官体验还是比较不错的。

介于这种体验,obsidian社区的开发者和flomo作者进行了联动,发布了obsidian memos,其整体的体验和flomo类似。

obsidian memos有一系列的解析规则,感兴趣的小伙伴可以深入的体验看看。目前我的设置是将obsidian的日记目录设置为logseq的/journals,模板文件为空白文件;同时修改logseq编辑器的首选日期页面格式(obsidian日记的日期格式需要和logseq编辑器的首选日期页面格式保持一致)。
整体的流程为:使用obsidian memos在移动端记录摘抄和想法,通过obsidian同步,就能在logseq中正常显示了。

别把县城不当城市

原文地址:https://baijiahao.baidu.com/s?id=1732720335444395427&wfr=spider&for=pc


本文解释的重点问题是:

中国县制的发展历史


Notes:

  • 中办、国办印发《关于推进以县城为重要载体的城镇化建设的意见》,强调以县域为基本单位推进城乡融合发展,并从以下四个方面推动县城的城镇化:全面落实取消县城落户限制政策;加快发展大城市周边县城,融入邻近大城市;引导人口流失县城转型发展;保障县城建设正常用地需求
  • 下一阶段的城市发展,将不再像以往那样大拆大建,而是更多考虑大小城市协调发展 ,既顺应县城人口流动的趋势,补齐县城的短板,在使基层得到实惠的同时,也避免过多人口只能涌到大城市寻找机会而带来的“城市病”。 ^yz3b26o
  • 几乎所有在现在人们看来是“城市”的,在古代大抵都是“县城”,古时候并不存在“市政府”的概念
  • 社会学家马克斯•韦伯有一个著名的断言:“中国无城市”,就是指中国没有像西方那样自治的市民共同体(尽管罗威廉主张像汉口可能是例外),甚至也没有“市民”,市镇也一直都未能成为一级政区
  • 日本的“县管市”的体制: 日本地方行政区划分为都(直辖市),道(省),府(地级市),县,市(县级市),町,村
  • 1927年,国民政府终于将部分城市从所属政区中划出来,分为两等:特别市(后改直辖市)和普通市(即省辖市)。两者划分的主要标准是人口:像上海这样人口过百万的称“特别市”,一般的普通市与县相当,但人口20万以下的市仍归县长管辖。目前台湾的行政区体制
  • “县级市只不过是县城更大一点的县”
  • 当下的县市体制浓缩了几十年来的发展,即便是中国人自己,也经常搞不清楚里面的复杂门道。全世界没有一个国家像中国这样,“市”可以表达如此多不同层级行政区的:既可能是直辖市(但像重庆其实是一个省),也可能是地级市(如苏州市),其中有一些还是比一般地级市权限更高的副省级市或计划单列市,更有许多县级市,而县级市是归地级市管还是省直管,差别也很大。
  • 实践证明,海南省取消地级政区层次,提高了行政管理效率,避免了县被地级市“刮”的可能,但这也带来了一些新问题:除了海口、三亚之外,其余各市县的发展没有重点,缺乏增长极带动,呈现低水平均质发展的局面。

Q:

中华人民共和国行政区划
由省级行政区、地级行政区、县级行政区、乡级行政区组成

  • 省级行政区:省、自治区、直辖市、特别行政区
  • 地级行政区:地级市、地区、自治州、盟
  • 县级行政区:市辖区、县级市、县、自治县、旗、自治旗、特区、林区
  • 乡级行政区:街道、镇、乡、民族乡、苏木、民族苏木、县辖区

误入集群的节点引发的shard unassigned线上故障

背景是对线上的es7集群(这里简称为集群A)进行动态扩容,A集群配置3个node节点,在进行节点重启时误重启了其他集群(这里简称为集群B)废弃的节点,导致AB两个集群不可用,red状态。

现象

  • AB两个集群red状态
  • A集群有节点offline
  • B集群节点都online,但多个index的主副分片unassigned

解决办法

这里先交代下最后的解决办法:

A集群
对于A集群,找到正确的es安装地址,动态扩容后重启即可。

B集群
而对于B集群就比较复杂些,着重解决shard unassigned问题。

  1. 检查哪些index的shard出现unassigned问题
    可以通过命令:GET _cat/shards?h=index,shard,prirep,state,unassigned.reason定位到出现问题的index。如果你平常是使用kibana来查询监控集群的,当集群status=red时,kibana是无法连接到集群的,也就无法使用Dev Tools。这里推荐你使用Cerebro,一款提供对于ElasticSearch更加友好的可视化操作支持的工具。直接执行cat apis
  2. 三思而后行
    要从出现问题的index角度出发,如果是无关紧要或者是已经下线不在使用的,可以直接删除;反之删除index操作要慎重。
    根据unassigned.reason具体问题具体分析,根据官方的解释有如下:
  • INDEX_CREATED:由于创建索引的API导致未分配。
  • CLUSTER_RECOVERED :由于完全集群恢复导致未分配。
  • INDEX_REOPENED :由于打开open或关闭close一个索引导致未分配。
  • DANGLING_INDEX_IMPORTED :由于导入dangling索引的结果导致未分配。
  • NEW_INDEX_RESTORED :由于恢复到新索引导致未分配。
  • EXISTING_INDEX_RESTORED :由于恢复到已关闭的索引导致未分配。
  • REPLICA_ADDED:由于显式添加副本分片导致未分配。
  • ALLOCATION_FAILED :由于分片分配失败导致未分配。
  • NODE_LEFT :由于承载该分片的节点离开集群导致未分配。
  • REINITIALIZED :由于当分片从开始移动到初始化时导致未分配(例如,使用影子shadow副本分片)。
  • REROUTE_CANCELLED :作为显式取消重新路由命令的结果取消分配。
  • REALLOCATED_REPLICA :确定更好的副本位置被标定使用,导致现有的副本分配被取消,出现未分配。

根据目前查询的结果来看,我是属于DANGLING_INDEX_IMPORTED

我做了哪些尝试

❎由于出现故障,导致分配分片的5次(默认)重试机会用完了,所以不会再自动分配,需要进行retry

POST /_cluster/reroute?retry_failed=true

❎调整index的副本数为0

curl -XPUT 'localhost:9200/<INDEX_NAME>/_settings' -d '{"number_of_replicas": 0}'

❎调整index的刷新时间为5m

curl -XPUT 'localhost:9200/<INDEX_NAME>/_settings' -d ' { "settings": { "index.unassigned.node_left.delayed_timeout": "5m" } }'

✅手动分配分片,将主分片分配(只丢失部分数据,出现问题的index均为不在使用的)

POST _cluster/reroute
{
  "commands": [
    {
      "allocate_stale_primary": {
        "index": "index_name",
        "shard": 4,
        "node": "node1",
        "accept_data_loss" : true
      }
    }
  ]
}

分析

搜罗下网上归纳的出现unassigned的主要原因,建议直接阅读原文:How to Resolve Unassigned Shards in Elasticsearch | Datadog

补充下

不同版本的es的reroute语法

ES2.x的reroute命令:

curl -XPOST 'localhost:9200/_cluster/reroute' -d '{
    "commands" : [ {
        "move" :
            {
              "index" : "test", "shard" : 0,
              "from_node" : "node1", "to_node" : "node2"
            }
        },
        {
          "allocate" : {
              "index" : "test", "shard" : 1, "node" : "node3",
              "allow_primary":true  (表示接受主分片数据丢失)
          }
        }
    ]
}'

ES5.x升级之后,已经把主分片的恢复和副本的恢复进行了区分,Cluster Reroute | Elasticsearch Reference [5.6] | Elastic

curl -XPOST 'localhost:9200/_cluster/reroute' -d '{
    "commands" : [ {
        "move" :
            {
              "index" : "test", "shard" : 0,
              "from_node" : "node1", "to_node" : "node2"
            }
        },
        {
          "allocate_replica" : {
              "index" : "test", "shard" : 1, "node" : "node3"
          }
        },
        {
            "allocate_empty_primary": {
              "index" : "test", "shard" : 1, "node" : "node3",
              "accept_data_loss":true (接受数据丢失)
          }
        }
    ]
}'

不同情况下手动分配分片的流程

  • red情况下手动分配主分配操作流程
    • 先查询未分配的主分片原来是在哪个节点上 GET /order_orderlist/_shard_stores
    • 将主分片分配(只丢失部分数据)
POST _cluster/reroute
{
  "commands": [
    {
      "allocate_stale_primary": {
        "index": "index_name",
        "shard": 4,
        "node": "node1",
        "accept_data_loss" : true
      }
    }
  ]
}

如果数据不重要,可以不用放到原来的节点上,直接新建一个空分片替代

 POST _cluster/reroute
{
  "commands": [
    {
      "allocate_empty_primary": {
        "index": "test_11",
        "shard": 2,
        "node": "node0",
        "accept_data_loss" : true
      }
    }
  ]
}
  • yellow情况下手动分配副本分片操作:
POST /_cluster/reroute
{ 
  "commands" :[
    { 
      "allocate_replica" : 
         { 
           "index" : "index_name", 
           "shard" : 0, 
           "node": "node1"
         }
      }
   ]
 }

主分片的恢复用allocate_empty_primary,而副本的恢复用allocate_replica

补充:在unassigned的分片比较多的时候,可以使用脚本

#!/bin/bash
for index in $(curl  -s 'http://localhost:9200/_cat/shards' | grep UNASSIGNED | awk '{print $1}' | sort | uniq); do
      for shard in $(curl  -s 'http://localhost:9200/_cat/shards' | grep UNASSIGNED | grep $index | awk '{print $2}' | sort | uniq); do
          echo  $index $shard
          curl -XPOST 'localhost:9200/_cluster/reroute' -d "{
              'commands' : [ {
                    'allocate' : {
                        'index' : $index,
                        'shard' : $shard,
                        'node' : 'Master',
                        'allow_primary' : true
                    }
                  }
              ]
          }"

          sleep 5
      done
  done

可以参考的几篇文章:

  • 总结得最整的是 https://www.datadoghq.com/blog/elasticsearch-unassigned-shards/
  • 单独针对主shard出现unassigned的解决可以看http://blog.kiyanpro.com/2016/03/06/elasticsearch/reroute-unassigned-shards/
    https://t37.net/how-to-fix-your-elasticsearch-cluster-stuck-in-initializing-shards-mode.html
    http://www.wklken.me/posts/2015/05/23/elasticsearch-issues.html
  • 单独针对副本shard出现unassigned的解决可以看
    https://z0z0.me/recovering-unassigned-shards-on-elasticsearch/
    https://dpatil1410.wordpress.com/2016/09/24/its-red-how-do-i-recover-unassigned-elasticsearch-shards/

最近的一些情况

最近,公司一拨裁员,因故承担了很多以往没接触过的工作。花了很多的时间去熟悉业务,也花了一点时间适应新的工作生活轨迹。和以前相比,多了些忙忙碌碌的身影,多了些飘落的秀发。但,生活的齿轮在走,需要用多情去对抗无情。多情的是身边的亲人和可爱的生灵,他们温暖依存。

  • 工作上,开始接手搜索工作后,由于兼顾广告和搜索两侧的产品需求,是比较忙碌的。最近开始将广告的需求剥离出去,交给其他同事负责。搜索这块,涉及到公司各个产品的搜索服务。整体需求和架构比较分散,且历经多次迭代,没有形成完整的流程和规范化,工作起来比较花费时间检验和排查。
  • 生活上,新房子的装修已经接近尾声,家电基本已经购置安装。下个月中旬要搬家啦,终于在厦门有了一个属于自己的家,麻雀虽小但五脏俱全,走简约温暖的风格。

  • 最近厦门经历了一拨又一波寒潮来袭。那叫一个冷,某些地势较高的山区气温直逼零度。潮湿的空气伴随着咸味海风,一吹,体感的温度进一步下降,冷的直打哆嗦。路上的也都行人匆匆忙忙,裹紧衣物。对于小动物,这种温度的变化来的更加敏感。瞧,这是来蹭床的,还呼呼大睡。

Pipenv vs Virtualenv vs Conda environment

目前,Python创建虚拟环境主要有三种方式,在这篇文章中,我想谈谈如何使用它们。

为什么需要虚拟环境?

在使用Python语言时,通过pip(pip3)来安装第三方包,但是由于pip的特性,系统中只能安装每个包的一个版本。但是在实际项目开发中,不同项目可能需要第三方包的不同版本,迫使我们需要根据实际需求不断进行更新或卸载相应的包,而如果我们直接使用本地的Python环境,会导致整体的开发环境相当混乱而不易管理,这时候我们就需要开辟一个独立干净的空间进行开发和部署,虚拟环境就孕育而生。

Virtualenv

Virtualenv 是目前最流行的 Python 虚拟环境配置工具,同时支持Python2和Python3,也可以为每个虚拟环境指定Python解释器。

请预先安装pip或者pip3(安装pip的三种方式),以pip3为例

一旦正常安装pip后,可使用以下命令安装Virtualenv:

pip3 install virtualenv

在终端或命令提示符下进入(cd)选择的目录搭建一个虚拟环境:

virtualenv venv

如果存在多个python解释器,可以选择指定一个Python解释器(比如python3.6),没有指定则由系统默认的解释器来搭建(变更默认的python版本可以看看 {% post_link Python/使用update-alternatives管理多个版本的Python %}):

virtualenv -p /usr/bin/python3.6 venv

将会在当前的目录中创建一个名venv的文件夹,这是一个独立的python运行环境,包含了Python可执行文件, 以及 pip库的一份拷贝,但第三方包需要重新安装。

要开始使用虚拟环境,其需要被激活:

source env/bin/activate

停用虚拟环境:

deactivate

virtualenv 的一个最大的缺点就是,每次开启虚拟环境之前要去虚拟环境所在目录下的 bin 目录下 source 一下 activate。这时候virtualenvwrapper出现了,它对不同的虚拟环境使用不同的目录进行管理,并且还省去了每次开启虚拟环境时候的 source 操作,使得虚拟环境更加好用。

pip3 install virtualenvwrapper

vim ~/.bashrc开始配置virtualenvwrapper:

export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh

接着执行 source ~/.bashrc(或./zshrc)。

注意:修改.bashrc还是.zshrc取决于你使用的那种 shell。

  • workon: 打印所有的虚拟环境;
  • mkvirtualenv xxx: 创建 xxx 虚拟环境,可以--python=/usr/bin/python3.6 指定python版本;
  • workon xxx: 使用 xxx 虚拟环境;
  • deactivate: 退出 xxx 虚拟环境;
  • rmvirtualenv xxx: 删除 xxx 虚拟环境。
  • lsvirtualenv : 列举所有的环境。
  • cdvirtualenv: 导航到当前激活的虚拟环境的目录中,比如说这样您就能够浏览它的 site-packages。
  • cdsitepackages: 和上面的类似,但是是直接进入到 site-packages 目录中。
  • lssitepackages : 显示 site-packages 目录中的内容。

PipEnv

pipenv 是 Pipfile 主要倡导者、requests 作者 Kenneth Reitz 写的一个命令行工具,主要包含了Pipfile、pip、click、requests和virtualenv,能够有效管理Python多个环境,各种第三方包及模块。

pipenv所解决的问题:

  • requirements.txt 依赖管理的局限
  • 多个项目依赖不同第三方库、包版本问题
  • 依赖分析

pipenv的特性:

  • pipenv集成了pip,virtualenv两者的功能,且完善了两者的一些缺陷。
  • 过去用virtualenv管理requirements.txt文件可能会有问题,Pipenv使用Pipfile和Pipfile.lock,后者存放将包的依赖关系,查看依赖关系是十分方便。
  • 各个地方使用了哈希校验,无论安装还是卸载包都十分安全,且会自动公开安全漏洞。
  • 通过加载.env文件简化开发工作流程。
  • 支持Python2 和 Python3,在各个平台的命令都是一样的。

可使用以下命令安装pipenv

pip3 install pipenv

接下来,通过使用以下命令创建一个新环境,在指定目录下创建虚拟环境, 会使用本地默认版本的python

pipenv install

如果要指定版本创建环境,可以使用如下命令

pipenv --two  # 使用当前系统中的Python2 创建环境
pipenv --three  # 使用当前系统中的Python3 创建环境
pipenv --python 3  # 指定使用Python3创建环境
pipenv --python 3.6  # 指定使用Python3.6创建环境
pipenv --python 2.7.14  # 指定使用Python2.7.14创建环境

激活虚拟环境

pipenv shell

删除虚拟环境

pipenv --rm

使用exit退出当前虚拟环境

Conda Environment

Anaconda(官方网站)就是可以便捷获取包且对包能够进行管理,同时对环境可以统一管理的发行版本。Anaconda包含了conda、Python在内的超过180个科学包及其依赖项。Anaconda也有自己的虚拟环境系统,称为conda。

可以通过以下命令创建虚拟环境

conda create --name environment_name python=3.6

激活虚拟环境

conda activate

conda环境的卸载

conda remove -n environment_name --all

什么是新能源汽车?

文章总结自少数派《新能源汽车凭什么取代燃油车?》

最近考虑购置人生第一款车,之前对于汽车的了解知之甚少,现在开始补充这方面的知识点。第一个问题:什么是新能源汽车?

维基百科对新能源汽车的定义:是指采用非常规的车用燃料作为动力来源(或使用常规的车用燃料、采用新型车载动力装置),综合车辆的动力控制和驱动方面的先进技术,形成的技术原理先进、具有新技术、新结构的汽车。

新能源汽车包括四大类型:

  • 混合动力电动汽车(HEV)
  • 纯电动汽车(BEV,包括太阳能汽车)
  • 燃料电池电动汽车(FCEV)
  • 其他新能源包括机械能(如超级电容器、飞轮、压缩空气等高效储能器)汽车等与非常规的车用燃料指除汽油、柴油之外的燃料,如天然气(NG)、液化石油气(LPG)、乙醇汽油(EG)、甲醇、二甲醚 。

下图是以能量来源及电动机参与驱动的程度进行分类:

图片来源:少数派 @硬哥

 

混合动力汽车(Hybrid Electric Vehicle,HEV)

目的:让电动机弥补发动机的不足,在内燃机的低效工况实现电驱(甚至完全电驱),大幅降低了油耗

图片来源:知乎 @00 后 NVH 工程师

日系车为代表:

  • 丰田 THS:行星齿轮混联式结构,电动机和发动机共同输出动力,不同工况下进行动力分流切换主力输出
  • 本田 IMMD:主串联式结构,发动机带着电机发电,再由电动机驱动,只在高速工况发动机才通过离合器切换为直接驱动
  • 日产 e-Power:纯串联式结构

 

插电式混合动力汽车(Plug-in Hybrid Electric Vehicle,PHEV)

在HEV基础上,把电池做大一点,可以外接充电

一般市区通勤仅靠充电勉强够用,开着像是纯电动车,而出远门时就可以用油,用电时成本很低,用油时也能省油

注意:有些纯为政策而魔改的 PHEV,在亏电时的驾驶感受和油耗表现不会比同壳燃油车更好,甚至会更差,结构还更复杂故障率更高。

 

增程式电动汽车(Extended Range Electric Vehicle,EREV)

HEV和PHEV,发动机参与驱动,而增程式的发动机只负责发电,完全由电动机来驱动。可以理解为:在纯电动车的基础上,多了增程发电系统

增程式电动车的电池普遍更大,纯电续航里程远高于插混,在市区完全可以当作纯电动车来开,而亏电或电量保持模式时的油耗也低于同级燃油车。

 

纯电动车(Battery Electric Vehicle,BEV)

结构最简单,电池供电,电机驱动。依赖于电池能量密度,目前最大的问题是充电慢和冬季衰减较大,需要逐渐增大电池提升续航里程,另一个提高充电功率加快充电速度,

 

燃料电池车(Fuel Cell Electric Vehicle,FCEV)

一般指的是氢燃料电池车,氢气与空气中的氧气在燃料电池堆中发生化学反应(并非燃烧),释放出电能。不过燃料电池堆普遍输出功率较低,所以在汽车上使用时,还需要搭配一块锂电池,锂电池与燃料电池堆协同充放电。这种结构听起来是不是与增程式 / 串联式混合动力极其相似?没错,燃料电池堆就相当于增程器,储氢罐相当于油箱,最终都是用电动机来驱动。

发展比较缓慢,存在很多问题。

 

电动机的优点:

  • 电动机零启特性,动力响应超快
  • 电动机驱动的平顺性无与伦比,秒杀最好的变速箱
  • 电机可以发电,动能回收更节能,省刹车片,还有单踏板模式

 

什么是单踏板模式?

只需要控制电门踏板,就可以实现起步、加速、减速(制动)等操作,利用动能回收的制动效果代替了刹车踏板的制动效果

优点:

  • 提供更好的动能回收,增加续航里程,纯电动车则可以将这种由于刹车浪费掉的动能,通过制动能量回收技术转变为电能重新存储于动力电池中
  • 为了提高城市拥堵路况驾驶的舒适性

 

完全没有充电条件的,推荐 HEV、EREV 和部分 PHEV

有充电条件的,第一辆或唯一一辆车,可以考虑 PHEV 或 EREV

有充电条件的,第二辆车,推荐 BEV

万物即可倍速 | #20220120

恰逢我家那位又开始准备考试了(对的,又。。),时常见她塞着耳机叼着笔看着教学视频,若有所思,完全沉浸在知识的海洋里。某次,好奇询问教学视频都包含哪些内容,她直接播放了一段。语速惊人,压根听不懂说了些什么,因为她开了倍速。

我是比较诧异的,我的习惯中倍速只是一个在特定情境下才会使用的选项。而我使用倍速只存在两种情况。一是所看的视频实在是不感冒,二是视频内容了然于胸,倍速是温故而知新,强化记忆而已。不揣测他人使用倍速背后的意图和目的,也不反对倍速,但我保持主观选择的权利。不可否认,这是个快速发展人人都在讲究高效的时代,碎片化的时间里要面对形形色色的诱惑和信息。时间是固定,选择是多变的。如何在有限的时间内作出更多的选择,是个难题。而这个难题的答案中,倍速是其中之一。

“这个女人。。。,这个男人。。。,这群人。。。”,是我日常生活中经常听到的一种开场白。固定的句式,固定的音乐,各种故事像生产线上的产品一样,只要套用固定的模板,就能“10分钟带你看完xxx”、“5分钟带你读完xxx”。之前,在和同事说到泛滥的影视解说视频的时候,彼此的观点是一致的:这类一味压缩取其精华的解说视频是对影视内容行业的一种打击,淹没了视频作品本身的内容价值,这种价值不仅仅是故事线的起承转合,也包括视频的画面、音乐、台词等等。

最近读了毒舌科技的《快进!快进!快进!我们终究坠入了「倍速世界」》,对文章表述的观点比较认同。文章不仅就目前的现状做了探讨也对倍速背后的消费心理和经济利益做了分析。文章认为倍数越快越上瘾,越短越上头,一旦开启,就再也停不下来,在平台、创作者和用户之间形成一个“快循环”。“快循环”的背后是一种越来越缺乏耐心的消费心理,这种心理配合上好奇心的加持,就期待更快的播放速度。

但受众在什么情况下需要倍速、在什么情况下拒绝倍速、如何清醒地使用倍速,这是可以主观选择的

这周,周围感冒咳嗽的同事多了一些,在这流感多发的季节,做好自身的保暖和防护工作是很重要的。如果不小心感冒咳嗽,也不用过于担心,及时就医,遵循医嘱科学吃药,早日康复。说到科学吃药这事,最近在少数派读到了一篇文章《药不能停,但也不能乱吃:为什么医嘱里要教你如何吃药?》,文章简单通俗,普及了一点关于吃药的那些事。

在家里时常听到奶奶说“刚才吃饭前又忘记吃药了,没事,等会补吃一下就好了”,以前可能对吃药这事没有过多的了解,认为只要吃了就行。其实,这是错的。这篇文章具体问题具体分析,从哪些药早上吃那些药晚上吃,到为什么要空腹吃为什么要饭后吃等等一些日常生活中会遇到的吃药场景,进行了说明和分析。

Effie快捷键列表

Effie 快捷键列表

基本操作

  • Ctrl+Alt+, 打开设置
  • Ctrl+1 展开/收缩左边栏
  • Shift+Ctrl+N 新建文件夹
  • Ctrl+N 新建文稿
  • Ctrl+Up 打开上一篇文稿
  • Ctrl+Down 打开下一篇文稿
  • Ctrl+Delete 删除选中文稿
  • Shift+Ctrl+S 把文稿导出成 EffieSheet 文件
  • Ctrl+6 字数统计
  • Shift+Ctrl+F 在文稿列表里查找
  • F11 进入/退出全屏

大纲

  • Tab 降低层级
  • Shift+Tab 提升层级
  • Ctrl+` 打开思维导图
  • Ctrl+/ 折叠/展开大纲

思维导图

  • Ctrl++ 放大思维导图
  • Ctrl+- 缩小思维导图
  • Ctrl+0 还原思维导图默认大小
  • Enter 插入主题
  • Tab 插入子主题
  • Ctrl+S 保存成图片
  • Ctrl+/ 折叠/展开子主题
  • Ctrl+Z 撤销
  • Shift+Ctrl+Z 重做
  • Del 删除

编辑区快捷键

  • Ctrl+Z 撤销
  • Shift+Ctrl+Z 重做
  • Ctrl+A 全选
  • Ctrl+X 剪切
  • Ctrl+C 复制
  • Ctrl+V 粘贴
  • Ctrl+B 加粗
  • Ctrl+I 斜体
  • Ctrl+L 清除标志
  • Ctrl+F 查找
  • F3 查找下一个
  • Ctrl+H 查找并替换
  • → 光标向右移动一个字符
  • ← 光标向左移动一个字符
  • ↑ 光标向上移动一行
  • ↓ 光标向下移动一行
  • Home 光标移动到当前行行首
  • End 光标移动到当前行行尾
  • Ctrl+Home 光标移动到文章开头
  • Ctrl+End 光标移动到文章末尾

2021反卷先锋们 | #20220113

2021年依旧是排队之年,有的继续内卷,有的开始关注自己。卷与不卷,生不由已。

🚩2021年度十大“反卷”

新周刊总结了过去一年那些与反卷抗争的先锋们,或许在面对自己不爱的生活时没有退出机制,想要努力活成心目中的样子。虽然年轻人的焦虑依旧存在,但至少开始作出改变。

摘录:

  • 对于内卷,人类学家项飙有过一个形象的比喻:“今天的内卷是一个陀螺式的死循环,我们要不断抽打自己,让自己就这么空转,每天不断地动员自己。因此,它是一个高度动态的陷阱,非常耗能。”
  • 反内卷并不完全等同于躺平,而是在不断的试错中找到自己真正热爱的东西,从而做到有的放矢。“100%的生活中,可能有80个方面你要佛系一点 ,但是另外20个里面,把全部的生命投入进去。”
  • 如果说内卷像一个我们每个人都不想去、却又不得不赴约的饭局,反卷则无疑需要爽约的勇气
  • “就算是最微小的成功,也值得我们为之欢欣鼓舞。只要道路是正确的,我们总能抵达终点”。
  • “我们早已习惯了被教育如何努力追求成就,做个成功者。但却鲜有人告诉我们,在此之前,如何接纳自我,如何做一个珍惜快乐的普通人。”
  • 如果说内卷源于每时每刻都在与他人对齐,反卷的关键或许在于专注自己。

🚩好好睡觉,被严重忽视的人生大事

2021年的最后一个月,我开始内卷的工作状态。突如起来的改变,一下子抛开坚持了3年的生活态度。慢慢开始发现,精神不振,记忆力下降,缺乏睡眠。

马修·沃克在其书《我们为什么要睡觉?》中,逐一分析了侵蚀我们睡眠自由的现代生活方式——电灯、iPad、酒精、恒定的室温以及需要打卡的上下班,并给出如何拥有健康睡眠的12条建议。

4点影响睡眠的要素:电灯、酒精、温度、工作

  • 电灯结束了我们睡觉的自然秩序
    1. 电灯会欺骗视交叉上核,限制褪黑激素的释放;
    2. 夜间使用LED设备会影响我们的自然睡眠节奏、睡眠质量及白天的清醒度;
    3. 调低、调暗你傍晚所处的房间里的灯光是一个良好的开始。
  • 酒精在夜间会破坏你的睡眠。
    1. 酒精前期的镇静剂作用,会让人陷入一种类似麻醉的状态;
    2. 酒精会将睡眠碎片化,用短暂的清醒把睡眠搅得支离破碎;
    3. 酒精是我们所知道的抑制快速眼动睡眠的最强力物质之一,如果长时间没有有梦睡眠,就会积累下需要获得快速眼动睡眠的巨大压力,被压抑的快速眼动睡眠压力强烈爆发,侵入清醒的意识中,从而引起幻觉、妄想和严重的方向感消失。这种可怕的精神异常状态的专业术语是“震颤性谵妄”。
  • 我们失去了适合睡眠的温度自由。
    1. 夜间褪黑激素水平不仅受到黄昏时日光衰减的控制,而且受到与日落一致的温度下降的控制。因此,环境中的光线和温度尽管相互独立,但依然协同作用,决定了夜间的褪黑激素水平,规划了理想的睡眠时间;
    2. 肢体的乱伸有助于保持身体核心的冷却
    3. 热水浴会让血液流到你的皮肤表面,让你看起来更加红润。当你离开浴缸时,皮肤表面那些扩张的血管会帮助你迅速地散发体内的热量,并且让你的核心体温骤然下降。因此,你才能更快地入睡。睡前的热水浴可以使健康成年人的深度非快速眼动睡眠增加10%到15%。
  • 只有人类有意过早终止睡眠
    1. 从睡眠中被人为惊醒的人将会遭受由神经系统的战斗或逃跑分支发生暴发性活动所引起的血压、心率急剧上升
    2. 如果惊醒你的心脏还不够糟糕的话,那么使用贪睡功能意味着你会在短时间内反复造成对心血管的伤害

12个建议:

  1. 坚持固定的睡眠时间
  2. 锻炼很有益,但不要在一天中太晚的时间进行
  3. 避免咖啡因和尼古丁的过度摄入
  4. 睡前避免喝酒精饮料
  5. 深夜避免大量进食和喝饮料
  6. 尽量避免使用会延迟或破坏睡眠的药物
  7. 下午 3 点以后不要午睡
  8. 睡前放松
  9. 睡前洗个热水澡
  10. 保持卧室幽暗凉爽,并且不要放置任何电子产品
  11. 适当晒晒太阳
  12. 醒着时不要躺在床上

🚩跟爱人聊天,一定要懂点玄学

刚步入婚姻殿堂的我,和另一半的相处之道定是必修课,看看文章学起来,反思下过往的相处方式,需要走的路还很长。最喜欢这篇文章的最后一句:

只要别忘了,你还爱她就好

摘录:

  • 当智商、情商还有社会学、经济学、心理学、学前教育和成功学这些乱七八糟的东西揉杂在一起的时候,真要懂点玄学的东西才能应对所有的未知。
  • 杨绛先生曾说,年轻的时候以为不读书不足以了解人生,直到后来才发现,如果不了解人生,其实是读不懂书的。
  • 这像极了成年人眼下看不清又道不明的人生,但与各式各样的“商”无关,而是残存了不少照本宣科的书生气,欠了些茶米油盐的烟火味。简单的做法是,她要讲感情的时候,你就讲感情,她想听过往的时候你就聊聊过往,她的道理永远是最好的道理,她的情绪永远是留有美景的四季。
  • 婚姻里的「对症下药」,更像是在注定会病的情况下,提前着手准备的各种方子,但吃久了也会伤身,而且治疗的过程总会有疼。
  • 不要总是在有了矛盾的时候才想着好好聊聊,也别在婚姻的日常里需要聊才去聊。
  • 请收起那些职业病,还有习惯性伪装下的虚情假意,也要放下自己那些医生、老师、经理、雇员,等等的身份,找回一点亲人的属性,还有爱人的牵绊。
  • 或许对不同的人来说,婚姻的境况大不相同,你遇到的人,经历的事,还有两个人各自的社会角色,都会增加彼此聊天的难度。但不管怎样,把这些都卸下来就好,以一个爱人的身份去对待另一个爱人。