笔记转载于GitHub项目https://github.com/NLP-LOVE/Introduction-NLP

13. 深度学习与自然语言处理

13.1 传统方法的局限

前面已经讲过了隐马尔可夫模型、感知机、条件随机场、朴素贝叶斯模型、支持向量机等传统机器学习模型,同时,为了将这些机器学习模型应用于 NLP,我们掌握了特征模板、TF-IDF、词袋向量等特征提取方法。而这些方法的局限性表现为如下:

  1. 数据稀疏

    首先,传统的机器学习方法不善于处理数据稀疏问题,这在自然语言处理领域显得尤为突出,语言是离散的符号系统,每个字符、单词都是离散型随机变量。我们通常使用独热向量(one-hot)来将文本转化为向量表示,指的是只有一个元素为1,其他元素全部为 0 的二进制向量。例如:

    祖国特征: ["中国","美国","法国"] (这里 N=3)

    中国 => 100

    美国 => 010

    法国 => 001

    上面的祖国特征只有 3 个还好,那如果是成千上万个呢?就会有很多的 0 出现,表现为数据的稀疏性。

  2. 特征模板

    语言具有高度的复合型。对于中文而言,偏旁部首构成汉字,汉字构成单词,单词构成短语,短语构成句子,句子构成段落,段落构成文章,随着层级的递进与颗粒度的增大,所表达的含义越来越复杂。

    这样的特征模板同样带来数据稀疏的困扰: 一个特定单词很常见,但两个单词的特定组合则很少见,三个单词更是如此。许多特征在训练集中仅仅出现一次,仅仅出现一次的特征在统计学上毫无意义。

  3. 误差传播

    现实世界中的项目,往往涉及多个自然语言处理模块的组合。比如在情感分析中,需要先进行分词,然后进行词性标注,根据词性标注过滤掉一些不重要的词,最后送入到朴素贝叶斯或者支持向量机等机器学习模块进行分类预测。

    这种流水线式的作业方式存在严重的误差传播问题,亦即前一个模块产生的错误被输入到下一个模块中产生更大的错误,最终导致了整个系统的脆弱性。

13.2 深度学习与优势

为了解决传统机器学习与自然语言处理中的数据稀疏、人工特征模板和误差传播等问题,人们将注意力转向了另一种机器学习潮流的研究--深度学习。

  1. 深度学习

    深度学习(Deep Leaming, DL )属于表示学习( Representation Learning )的范畴,指的是利用具有一定“深度”的模型来自动学习事物的向量表示(vectorial rpresenation)的一种学习范式。目前,深度学习所采用的模型主要是层数在一层以上的神经网络。如果说在传统机器学习中,事物的向量表示是利用手工特征模板来提取稀疏的二进制向量的话,那么在深度学习中,特征模板被多层感知机替代。而一旦问题被表达为向量,接下来的分类器一样可以使用单层感知机等模型,此刻深度学习与传统手法毫无二致,殊途同归。所以说深度学习并不神秘,通过多层感知机提取向量才是深度学习的精髓。

    对于深度学习原理,在之前我的博客中已经介绍了,详细请点击:

    http://mantchs.com/2019/08/04/DL/Neural%20Network/

  2. 用稠密向量解决数据稀疏

    神经网络的输出为样本 x 的一个特征向量 h。由于我们可以自由控制神经网络隐藏层的大小,所以在隐藏层得到的 h 的长度也可以控制。即便输人层是词表大小的独热向量、维度高达数十万,隐藏层得到的特征向量依然可以控制在很小的体积,比如100维。

    这样的 100 维向量是对词语乃至其他样本的抽象表示,含有高度浓缩的信息。正因为这些向量位于同一个低维空间,我们可以很轻松地训练分类器去学习单词与单词、文档与文档、图片与图片之间的相似度,甚至可以训练分类器来学习图片与文档之间的相似度。由表示学习带来的这一切, 都是传统机器学习方法难以实现的。

  3. 用多层网络自动提取特征表示

    神经网络两层之间一般全部连接(全连接层),并不需要人们根据具体问题具体设计连接方式。这些隐藏层会根据损失函数的梯度自动调整多层感知机的权重矩阵,从而自动学习到隐陬层的特征表示。

    该过程完全不需要人工干预,也就是说深度学习从理论上剥夺了特征模板的用武之地。

  4. 端到端的设计

    由于神经网络各层之间、各个神经网络之间的“交流语言”为向量,所以深度学习工程师可以轻松地将多个神经网络组合起来,形成一种端到端的设计。比如之前谈到的情感分析案例中,一种最简单的方案是将文档的每个字符的独热向量按顺序输入到神经网络中,得到整个文档的特征向量。然后将该特征向量输入到多项逻辑斯谛回归分类器中,就可以分类出文档的情感极性了。

    整个过程既不需要中文分词,也不需要停用词过滤。因为神经网络按照字符顺序模拟了人类阅读整篇文章的过程,已经获取到了全部的输人。

13.3 word2vec

作为连接传统机器学习与深度学习的桥梁,词向量一直是入门深度学习的第一站。词向量的训练方法有很多种,word2vec 是其中最著名的一种,还有 fastText、Glove、BERT和最近很流行的 XLNet 等。

  1. word2vec 的原理在我博客里已经讲解过了,详细介绍见:

    http://mantchs.com/2019/08/22/NLP/Word%20Embeddings/

  2. 训练词向量

    了解了词向量的基本原理之后,本节介绍如何调用 HanLP 中实现的词向量模块,该模块接受的训练语料格式为以空格分词的纯文本格式,此处以 MSR 语料库为例。训练代码如下(自动下载语料库):

    1. from pyhanlp import *
    2. import zipfile
    3. import os
    4. from pyhanlp.static import download, remove_file, HANLP_DATA_PATH
    5. def test_data_path():
    6. """
    7. 获取测试数据路径,位于$root/data/test,根目录由配置文件指定。
    8. :return:
    9. """
    10. data_path = os.path.join(HANLP_DATA_PATH, 'test')
    11. if not os.path.isdir(data_path):
    12. os.mkdir(data_path)
    13. return data_path
    14. ## 验证是否存在语料库,如果没有自动下载
    15. def ensure_data(data_name, data_url):
    16. root_path = test_data_path()
    17. dest_path = os.path.join(root_path, data_name)
    18. if os.path.exists(dest_path):
    19. return dest_path
    20. if data_url.endswith('.zip'):
    21. dest_path += '.zip'
    22. download(data_url, dest_path)
    23. if data_url.endswith('.zip'):
    24. with zipfile.ZipFile(dest_path, "r") as archive:
    25. archive.extractall(root_path)
    26. remove_file(dest_path)
    27. dest_path = dest_path[:-len('.zip')]
    28. return dest_path
    29. sighan05 = ensure_data('icwb2-data', 'http://sighan.cs.uchicago.edu/bakeoff2005/data/icwb2-data.zip')
    30. msr_train = os.path.join(sighan05, 'training', 'msr_training.utf8')
    31. ## ===============================================
    32. ## 以下开始 word2vec
    33. IOUtil = JClass('com.hankcs.hanlp.corpus.io.IOUtil')
    34. DocVectorModel = JClass('com.hankcs.hanlp.mining.word2vec.DocVectorModel')
    35. Word2VecTrainer = JClass('com.hankcs.hanlp.mining.word2vec.Word2VecTrainer')
    36. WordVectorModel = JClass('com.hankcs.hanlp.mining.word2vec.WordVectorModel')
    37. # 演示词向量的训练与应用
    38. TRAIN_FILE_NAME = msr_train
    39. MODEL_FILE_NAME = os.path.join(test_data_path(), "word2vec.txt")
    40. def train_or_load_model():
    41. if not IOUtil.isFileExisted(MODEL_FILE_NAME):
    42. if not IOUtil.isFileExisted(TRAIN_FILE_NAME):
    43. raise RuntimeError("语料不存在,请阅读文档了解语料获取与格式:https://github.com/hankcs/HanLP/wiki/word2vec")
    44. trainerBuilder = Word2VecTrainer();
    45. return trainerBuilder.train(TRAIN_FILE_NAME, MODEL_FILE_NAME)
    46. return load_model()
    47. def load_model():
    48. return WordVectorModel(MODEL_FILE_NAME)
    49. wordVectorModel = train_or_load_model() # 调用函数训练 word2vec
  3. 单词语义相似度

    有了词向量之后,最基本的应用就是查找与给定单词意义最相近的前 N 个单词。

    1. # 打印 单词语义相似度
    2. def print_nearest(word, model):
    3. print(
    4. "\n Word "
    5. "Cosine\n------------------------------------------------------------------------")
    6. for entry in model.nearest(word):
    7. print("%50s\t\t%f" % (entry.getKey(), entry.getValue()))
    8. print_nearest("上海", wordVectorModel)
    9. print_nearest("美丽", wordVectorModel)
    10. print_nearest("购买", wordVectorModel)
    11. print(wordVectorModel.similarity("上海", "广州"))

    结果如下:

    1. Word Cosine
    2. ------------------------------------------------------------------------
    3. 广州 0.616240
    4. 天津 0.564681
    5. 西安 0.500929
    6. 抚顺 0.456107
    7. 深圳 0.454190
    8. 浙江 0.446069
    9. 杭州 0.434974
    10. 江苏 0.429291
    11. 广东 0.407300
    12. 南京 0.404509
    13. Word Cosine
    14. ------------------------------------------------------------------------
    15. 装点 0.652887
    16. 迷人 0.648911
    17. 恬静 0.634712
    18. 绚丽 0.634530
    19. 憧憬 0.616118
    20. 葱翠 0.612149
    21. 宁静 0.599068
    22. 清新 0.592581
    23. 纯真 0.589360
    24. 景色 0.585169
    25. Word Cosine
    26. ------------------------------------------------------------------------
    27. 0.521070
    28. 购得 0.500480
    29. 选购 0.483097
    30. 购置 0.480335
    31. 采购 0.469803
    32. 出售 0.469185
    33. 低收入 0.461131
    34. 分期付款 0.458573
    35. 代销 0.456689
    36. 高价 0.456320
    37. 0.6162400245666504

    其中 Cosine 一栏即为两个单词之间的余弦相似度,是一个介于 -1 和 1 之间的值。

  4. 词语类比

    将两个词语的词向量相减,会产生一个新向量。通过与该向量做点积,可以得出一个单词与这两个单词的差值之间的相似度。在英文中,一个常见的例子是 king - man + woman = queen,也就是说词向量的某些维度可能保存着当前词语与皇室的关联程度,另一些维度可能保存着性别信息。


    1. # param A: 做加法的词语
    2. # param B:做减法的词语
    3. # param C:做加法的词语
    4. # return:与(A-B+C) 语义距离最近的词语及其相似度列表
    5. print(wordVectorModel.analogy("日本", "自民党", "共和党"))

    结果如下:

    1. [美国=0.71801066, 德米雷尔=0.6803682, 美国国会=0.65392816, 布什=0.6503047, 华尔街日报=0.62903535, 国务卿=0.6280117, 舆论界=0.6277531, 白宫=0.6175594, 驳斥=0.6155998, 最惠国待遇=0.6062231]
  5. 短文本相似度

    我们将短文本中的所有词向量求平均,就能将这段短文本表达为一个稠密向量。于是我们就可以衡量任意两端短文本之间鹅相似度了。

    1. # 文档向量
    2. docVectorModel = DocVectorModel(wordVectorModel)
    3. documents = ["山东苹果丰收",
    4. "农民在江苏种水稻",
    5. "奥运会女排夺冠",
    6. "世界锦标赛胜出",
    7. "中国足球失败", ]
    8. print(docVectorModel.similarity("山东苹果丰收", "农民在江苏种水稻"))
    9. print(docVectorModel.similarity("山东苹果丰收", "世界锦标赛胜出"))
    10. print(docVectorModel.similarity(documents[0], documents[1]))
    11. print(docVectorModel.similarity(documents[0], documents[4]))

    结果如下:

    1. 0.6743720769882202
    2. 0.018603254109621048
    3. 0.6743720769882202
    4. -0.11777809262275696

    类似的,可以通过调用 nearest 接口查询与给定单词最相似的文档

    1. def print_nearest_document(document, documents, model):
    2. print_header(document)
    3. for entry in model.nearest(document):
    4. print("%50s\t\t%f" % (documents[entry.getKey()], entry.getValue()))
    5. def print_header(query):
    6. print(
    7. "\n%50s Cosine\n------------------------------------------------------------------------" % (query))
    8. for i, d in enumerate(documents):
    9. docVectorModel.addDocument(i, documents[i])
    10. print_nearest_document("体育", documents, docVectorModel)
    11. print_nearest_document("农业", documents, docVectorModel)
    12. print_nearest_document("我要看比赛", documents, docVectorModel)
    13. print_nearest_document("要不做饭吧", documents, docVectorModel)

    结果如下:

    1. 体育 Cosine
    2. ------------------------------------------------------------------------
    3. 世界锦标赛胜出 0.256444
    4. 奥运会女排夺冠 0.206812
    5. 中国足球失败 0.165934
    6. 山东苹果丰收 -0.037693
    7. 农民在江苏种水稻 -0.047260
    8. 农业 Cosine
    9. ------------------------------------------------------------------------
    10. 农民在江苏种水稻 0.393115
    11. 山东苹果丰收 0.259620
    12. 中国足球失败 -0.008700
    13. 世界锦标赛胜出 -0.063113
    14. 奥运会女排夺冠 -0.137968
    15. 我要看比赛 Cosine
    16. ------------------------------------------------------------------------
    17. 奥运会女排夺冠 0.531833
    18. 世界锦标赛胜出 0.357246
    19. 中国足球失败 0.268507
    20. 山东苹果丰收 0.000207
    21. 农民在江苏种水稻 -0.022467
    22. 要不做饭吧 Cosine
    23. ------------------------------------------------------------------------
    24. 农民在江苏种水稻 0.232754
    25. 山东苹果丰收 0.199197
    26. 奥运会女排夺冠 -0.166378
    27. 世界锦标赛胜出 -0.179484
    28. 中国足球失败 -0.229308

13.4 基于神经网络的高性能依存句法分析器

  1. Arc-Standard转移系统

    不同之前介绍的 Arc-Eager,该依存句法器基于 Arc-Standard 转移系统,具体动作如下:

    动作名称 条件 解释
    Shift 队列 β 非空 将队首单词 i 压栈
    LeftArc 栈顶第二个单词 将栈顶第二个单词 i 的支配词设为栈顶单词 j,即 i 作为 j 的子节点
    RightArc 将栈顶单词 j 的支配词设为栈顶第二个单词 i,即 j作为 i 的子节点

    两个转移系统的逻辑不同,Arc-Eager 自顶而下地构建,而 Arc-Standard 要求右子树自底而上地构建。虽然两者的复杂度都是 O(n),然而可能由于 Arc-Standard 的简洁性(转移动作更少),它更受欢迎。

  2. 特征提取

    虽然神经网络理论上可以自动提取特征,然而这篇论文作为开山之作,依然未能脱离特征模板。所有的特征分为三大类,即:

    • 单词特征。
    • 词性特征。
    • 已经确定的子树中的依存标签特征。

    接着,句法分析器对当前的状态提取上述三大类特征,分别记作 w、t 和 l。不同于传统方法,此处为每个特征分配一个向量,于是得到三个稠密向量 Xw、Xt 和 Xl。接着,将这三个向量拼接起来输人到含有一个隐藏层的神经网络,并且使用立方函数激活,亦即得到隐藏层的特征向量:

    \[h=\left(W_{1}\left(x^{w} \oplus x^{t} \oplus x^{l}\right)\right)^{3}
    \]

    接着,对于 k 种标签而言,Arc-Standard 一共存在 2k +1 种可能的转移动作。此时只需将特征向量 h 输人到多元逻辑斯谛回归分类器(可以看作神经网络中的输出层)中即可得到转移动作的概率分布:

    \[p=softmax\left(W_{2} h\right)
    \]

    最后选取 p 中最大概率所对应的转移动作并执行即可。训练时,采用 softmax 交叉熵损失函数并且以随机梯度下降法优化。

  3. 实现代码

    1. from pyhanlp import *
    2. CoNLLSentence = JClass('com.hankcs.hanlp.corpus.dependency.CoNll.CoNLLSentence')
    3. CoNLLWord = JClass('com.hankcs.hanlp.corpus.dependency.CoNll.CoNLLWord')
    4. IDependencyParser = JClass('com.hankcs.hanlp.dependency.IDependencyParser')
    5. NeuralNetworkDependencyParser = JClass('com.hankcs.hanlp.dependency.nnparser.NeuralNetworkDependencyParser')
    6. parser = NeuralNetworkDependencyParser()
    7. sentence = parser.parse("徐先生还具体帮助他确定了把画雄鹰、松鼠和麻雀作为主攻目标。")
    8. print(sentence)
    9. for word in sentence.iterator(): # 通过dir()可以查看sentence的方法
    10. print("%s --(%s)--> %s" % (word.LEMMA, word.DEPREL, word.HEAD.LEMMA))
    11. print()
    12. # 也可以直接拿到数组,任意顺序或逆序遍历
    13. word_array = sentence.getWordArray()
    14. for word in word_array:
    15. print("%s --(%s)--> %s" % (word.LEMMA, word.DEPREL, word.HEAD.LEMMA))
    16. print()
    17. # 还可以直接遍历子树,从某棵子树的某个节点一路遍历到虚根
    18. CoNLLWord = JClass("com.hankcs.hanlp.corpus.dependency.CoNll.CoNLLWord")
    19. head = word_array[12]
    20. while head.HEAD:
    21. head = head.HEAD
    22. if (head == CoNLLWord.ROOT):
    23. print(head.LEMMA)
    24. else:
    25. print("%s --(%s)--> " % (head.LEMMA, head.DEPREL))

    依存关系详细见 Chinese Dependency Treebank 1.0 的定义。

13.5 结语

  1. 自然语言处理是一门日新月异的学科,在深度学习的时代更是如此。在学术界,即便是当前最先进的研究,在仅仅两个月后很快就会被突破。本系列文章所提供的知识只不过是那些入门级的基础知识而已。

  2. 神经网络中两个常用的特征提取器: 用于时序数据的递归神经网络 RNN 以及用于空间数据的卷积神经网络 CNN。其中,RNN 在自然语言处理领域应用得最为广泛。RNN 可以处理变长的输入,这正好适用于文本。特别是 RNN 家族中的 LSTM 网络,可以记忆大约 200 左右的单词,为建模句子中单词之间的长距离依存创造了条件。然而,RNN 的缺陷在于难以并行化。如果需要捕捉文本中的 n 元语法的话,CNN 反而更胜一筹,并且在并行化方面具备天然优势。考虑到文档一般较长, 许多文档分类模型都使用 CNN 来构建。而句子相对较短,所以在句子颗粒度上进行的基础 NLP 任务(中文分词、词性标注、命名实体识别和句法分析等)经常采用 RNN 来实现。

  3. 在词嵌入的预训练方面,word2vec 早已是明日黄花。Facebook 通过将词语内部的构词信息引人 Skip-Gram 模型,得到的 fastText 可以为任意词语构造词向量,而不要求该词语一定得出现在语料库中。但是,无论是 word2vec 还是 fastText,都无法解决一词多义的问题。因为多义词的消歧必须根据给定句子的上下文才能进行,这催生了一系列能够感知上下文的词语表示方法。

    其中,华盛顿大学提出了 ELMO,即一个在大规模纯文本上训练的双向 LSTM 语言模型。ELMo 通过读人上文来预测当前单词的方式为词嵌人引入了上下文信息。Zalando Research 的研究人员则将这一方法应用到了字符级别,得到了上下文字符串嵌入,其标注器取得了目前最先进的准确率。而 Google 的 BERT 模型则通过一种高效的双向Transformer网络同时对上文和下文建模,在许多NLP任务上取得了惊人的成绩。

  4. 另一些以前认为很难的 NLP 任务,比如自动问答和文档摘要等,在深度学习时代反而显得非常简单。许多 QA 任务归结为衡量问题和备选答案之间的文本相似度,这恰好是具备注意力机制的神经网络所擅长的。而文档摘要涉及的文本生成技术,又恰好是 RNN 语言模型所擅长的。在机器翻译领域,Google 早已利用基于神经网络的机器翻译技术淘汰了基于短语的机器翻译技术。目前,学术界的流行趋势是利用 Transformer 和注意力机制提取特征。

总之,自然语言处理的未来图景宏伟而广阔。自然语言处理入门系列文章就作为这条漫漫长路上的一块垫脚石,希望给予读者一些必备的入门概念。至于接下来的修行,前路漫漫,与君共勉。

13.6 GitHub

HanLP何晗--《自然语言处理入门》笔记:

https://github.com/NLP-LOVE/Introduction-NLP

目录


章节
第 1 章:新手上路
第 2 章:词典分词
第 3 章:二元语法与中文分词
第 4 章:隐马尔可夫模型与序列标注
第 5 章:感知机分类与序列标注
第 6 章:条件随机场与序列标注
第 7 章:词性标注
第 8 章:命名实体识别
第 9 章:信息抽取
第 10 章:文本聚类
第 11 章:文本分类
第 12 章:依存句法分析
第 13 章:深度学习与自然语言处理

13.深度学习(词嵌入)与自然语言处理--HanLP实现的更多相关文章

  1. [DeeplearningAI笔记]序列模型2.3-2.5余弦相似度/嵌入矩阵/学习词嵌入

    5.2自然语言处理 觉得有用的话,欢迎一起讨论相互学习~Follow Me 2.3词嵌入的特性 properties of word embedding Mikolov T, Yih W T, Zwe ...

  2. 吴恩达《深度学习》-课后测验-第五门课 序列模型(Sequence Models)-Week 2: Natural Language Processing and Word Embeddings (第二周测验:自然语言处理与词嵌入)

    Week 2 Quiz: Natural Language Processing and Word Embeddings (第二周测验:自然语言处理与词嵌入) 1.Suppose you learn ...

  3. DeepLearning.ai学习笔记(五)序列模型 -- week2 自然语言处理与词嵌入

    一.词汇表征 首先回顾一下之前介绍的单词表示方法,即one hot表示法. 如下图示,"Man"这个单词可以用 \(O_{5391}\) 表示,其中O表示One_hot.其他单词同 ...

  4. ng-深度学习-课程笔记-16: 自然语言处理与词嵌入(Week2)

    1 词汇表征(Word representation) 用one-hot表示单词的一个缺点就是它把每个词孤立起来,这使得算法对词语的相关性泛化不强. 可以使用词嵌入(word embedding)来解 ...

  5. Coursera Deep Learning笔记 序列模型(二)NLP & Word Embeddings(自然语言处理与词嵌入)

    参考 1. Word Representation 之前介绍用词汇表表示单词,使用one-hot 向量表示词,缺点:它使每个词孤立起来,使得算法对相关词的泛化能力不强. 从上图可以看出相似的单词分布距 ...

  6. NLP&深度学习:近期趋势概述

    NLP&深度学习:近期趋势概述 摘要:当NLP遇上深度学习,到底发生了什么样的变化呢? 在最近发表的论文中,Young及其同事汇总了基于深度学习的自然语言处理(NLP)系统和应用程序的一些最新 ...

  7. Deep-Learning-with-Python] 文本序列中的深度学习

    https://blog.csdn.net/LSG_Down/article/details/81327072 将文本数据处理成有用的数据表示 循环神经网络 使用1D卷积处理序列数据 深度学习模型可以 ...

  8. DLNg序列模型第二周NLP与词嵌入

    1.使用词嵌入 给了一个命名实体识别的例子,如果两句分别是“orange farmer”和“apple farmer”,由于两种都是比较常见的,那么可以判断主语为人名. 但是如果是榴莲种植员可能就无法 ...

  9. [DeeplearningAI笔记]序列模型2.1-2.2词嵌入word embedding

    5.2自然语言处理 觉得有用的话,欢迎一起讨论相互学习~Follow Me 2.1词汇表征 Word representation 原先都是使用词汇表来表示词汇,并且使用1-hot编码的方式来表示词汇 ...

随机推荐

  1. spring boot通过@Bean注解定义一个Controller

    功能需求 提供一个公共的jar包给其他业务模块依赖,需要在这个公共的jar中暴露一个restful API 采用spring auto config机制,在公共jar包中定义spring.factor ...

  2. opencv利用svm训练

    ]]]]]])rand2 = np.array([[]]]]]])label = np.array([[]]]]]]]]]]])data = np.vstack((rand1]]])pt_data = ...

  3. Scala实践2

    一.Scala基本类型和操作 1.1  基本类型 Scala的基本类型与Java基本类型相同,都是byte.short.int.long.char.string.float.double.boolea ...

  4. postman传递当前时间戳

    有时我们在请求接口时,需要带上当前时间戳这种动态参数,那么postman能不能自动的填充上呢. 1请求动态参数(例如时间戳) 直接在参数值写 {{$timestamp}} 如下: 我们也可以使用pos ...

  5. Spring Boot2 系列教程 (十一) | 整合数据缓存 Cache

    如题,今天介绍 SpringBoot 的数据缓存.做过开发的都知道程序的瓶颈在于数据库,我们也知道内存的速度是大大快于硬盘的,当需要重复获取相同数据时,一次又一次的请求数据库或者远程服务,导致大量时间 ...

  6. python 生成器,迭代器,闭包,装饰器

    1.生成器,迭代器,闭包,装饰器的优点 生成器就是一类特殊的迭代器 迭代器的优点也即生成器的优点: 1.节约内存.python在使用生成器时对延迟操作提供了支持. 2.迭代到下一次的调用时,所使用的参 ...

  7. 【X86】---X86处理器大小端的数据存储验证

    之前也关注过大小端的存储,可能时间久了,加之又之前的电脑抽象换成了当前的处理器寄存器的值判断,导致自己总是有点蒙圈.看Spec手册的时候,有时会无法与手册中某个Bit的值与RU/RW工具读出来的对应上 ...

  8. postman的测试,用对象接收所有的字符串

    1.post请求 Headers: Content-Type  application/json { "taskId":"1000001161", " ...

  9. 用ModelAndView返回视图结果返回的是对应RequestMapping拼接的路径

    今天,遇到一个贼坑的问题,就是我明明可以将逻辑视图名视图存入ModelAndView,结果返回的页面信息是RequestMapping拼接的视图解析路径,最后经过检查多遍代码,发现原来是ModelAn ...

  10. 9.Super详解

    super注意点: surper()是调用父类的构造方法,而且必须在构造方法的第一个 super必须只能出现在子类的方法或者构造方法中! super()和this()不能同时调用构造方法! Vs th ...