0%

NLP主要包括自然语言理解(NLU)和自然语言生成(NLG)。纽约大学和华盛顿大学等创建了一个多任务的NLP的基准和分析平台,即GLUE(general language understanding evaluation).GLUE九项任务涉及到自然语言推断、文本蕴含、情感分析、语义相似等多个任务。

GLUE共有九个任务,分别是CoLA、SST-2、MRPC、STS-B、QQP、MNLI、QNLI、RTE、WNLI。如下图图2所示,可以分为三类,分别是单句任务,相似性和释义任务.

背景知识

1948年,将全军各地的部队按地域划分为四大野战军。

  • 西北野战军:彭德怀、张宗逊、习仲勋
  • 中原野战军:刘伯承、邓小平、李达
  • 华东野战军:陈毅、粟裕、张云逸
  • 东北野战军:林彪、罗荣桓、刘亚楼

1949年,全国即将解放,按照地域划分不合适,西北改为一野,中原改为二野,华东改为三野,东北改为四野,还成立了华北野战军,受中央直接指挥。

1949年1月15日,中共中央军委下达了《关于野战军番号改按序数排列的决定》,将原西北野战军改编为“第一野战军”,彭德怀任司令员兼政治委员;将原中原野战军改编为“第二野战军”,刘伯承任司令员,邓小平任政治委员;将原华东野战军改编为“第三野战军”,陈毅任司令员兼政治委员,粟裕任副司令员兼第二副政治委员;将原东北野战军改编为“第四野战军”,林彪任司令员,罗荣桓任政治委员。将原华北军区的部队改编为“华北野战军”,受毛泽东、中央军委直接领导和指挥。在人民解放军的序列中,形成了五大野战军:“一野”、“二野”、“三野”、“四野”和“华野”。

辽沈战役

当时国民党大军别分割在长春、沈阳、锦州,
长春:郑洞国,曾泽生
沈阳:卫立煌
锦州:范汉杰

美国建议蒋介石撤出东北,这样的话会给华北的解放军带来巨大的压力。所以毛主席指示东野的林罗刘,要把国民党军封闭在东北各个歼灭。

林彪想法:攻打长春,围点打援
主席想法:如果长春守军被歼灭,卫立煌就会放弃东北。而如果攻下锦州,可以关门打狗。
但我军主力在哈尔滨,而且补给线需要从北到南,要输送到锦州,经过的铁路沿线可能会被破坏。
蒋介石想让卫立煌将主力从沈阳撤到锦州,这样可进可退。卫立煌担心路途中被林彪歼灭,打算居城固守。

但是攻打长春后,卫立煌并不派兵支援,只能南下。主席让林彪全力打锦州,才能让卫立煌放心来支援。
蒋介石部署:东西合击。

蒋介石向锦州西部的葫芦岛增兵,林彪感觉压力很大,左边有葫芦岛军队,背后有沈阳长春军队,想回头打长春。
最后决定还是按照军委的部署,阻击葫芦岛,攻打锦州,防备沈阳的廖耀湘军团。

国民党支援锦州打算从塔山路过,沈阳的廖耀湘也决定西边的军队能到达锦州,自己就出兵救援。所以塔山十分重要。
守方是四纵,攻方是独立95师,都是王牌部队。塔山受到巨大的威胁,林彪考虑是否把总预备队调上。

此时,廖耀湘从沈阳出发北进,占领彰武,切断了林彪从北向南运输的大动脉。林彪反而觉得轻松,因为廖耀湘是和前往锦州的相反前进。

廖耀湘想法:等着塔山突破,林彪就没有多余的军力来打自己,他和卫立煌都不愿为了锦州的范汉杰损失自己的力量。

攻打锦州:最主要的是外围的配水池。锦州守军因为有两路援军,还有很强的战斗意志,连续反扑。后来,锦州被攻破,范汉杰被俘虏。
蒋介石让长春的郑洞国向东南方向撤退,而城内的六十军军长曾泽生已经起义。郑洞国准备自杀,后来投降。

四野接下来的目标就是锦西和葫芦岛,然后就是沈阳的廖耀湘。

蒋介石的方略:以黑山、大虎山进攻,营造向锦州前进的假象,主力经大虎山东南,向营口转进。
林彪看出意图,放弃锦西、葫芦岛方案,全力围歼廖耀湘兵团。一方面守住黑山,一方面占领营口。
廖耀湘攻击黑山三天,放弃,准备转向营口。独立二师偶遇廖耀湘,将其打退。廖耀湘被包围。廖耀湘向沈阳撤退。

淮海战役

东部战争:先切断李弥兵团和黄百韬兵团的联系,再吃掉黄百韬兵团。

西部战争:刘邓攻占郑州,然后直出徐州、蚌埠一线,牵制孙元良、刘汝明。刘伯承牵制左下部队。

蒋介石让黄百韬西渡运河,从曹八集撤到徐州。黄百韬等待海州的李延年和44军,使得黄百韬兵团彻底陷入了华野的合围之中。
东部的第三绥靖区两个军起义,给华野让出道路,华野抢先占领曹八集,堵住了黄百韬撤退的道路。

杜聿明计划,调集孙元良、李弥邱清泉先击败刘伯承,再向东击败粟裕。国防部部署,邱、李兵团向东营救黄百韬,黄维兵团向徐州急进,群集一团。

南边有李延年、刘汝明兵团,西边有黄维兵团,邱清泉、李弥组成的东援部队也从徐州出发。黄百韬在碾庄也击退了华野的进攻。

此时,中野要抢占宿县。因为此时孙元良刚刚由南向北到达徐州,而黄维、刘汝明等还在南部。
蒋介石称自己部署为长蛇阵,共产党将黄百韬的蛇头掐断,中野机动兵团缠住蛇尾的黄维兵团,中野主力在宿县拦腰截断。孤立徐州的刘峙集团。

中央决定围歼邱清泉、李弥兵团,但是遭到其后部强烈抵抗,遂撤退。而且黄百韬的部队也难以消灭。于是总前委决定,先消灭黄百韬,补充兵力,再打黄维,最后解决邱、李。主席同意了这个放弃诱奸邱、李的计划,集中优势兵力发起对黄百韬的总攻。

全力攻击碾庄,在碾庄被攻占后,邱、李兵团距离碾庄还有20里。

第一阶段复盘:前期很不占优势,虽然吃掉了黄百韬兵团,但是部队损失严重,华野大伤元气。而刘伯承的中野还要面对黄维兵团攻占宿县。

中野想吃掉黄维兵团,又担心南部的李延年、刘汝明兵团支援。但主席说蒋军防御尚可,不会主动攻击的。
主席并派刚歼灭黄百韬的华野抽调一部分兵力支援中野。黄维企图突围,但是110师起义,并堵住了敌人的突围。
战后粟裕说,中野人数少、装备差,面对的敌人也是精锐,能歼灭黄维十分不易。


此时蒋介石的局势:平津的傅作义兵团被包围,胡宗南在西北被彭德怀死死咬住,华中的白崇禧处处掣肘,以李宗仁为首的党内势力蠢蠢欲动。所以蒋介石想保存实力,维持统治。所以想放弃黄维兵团,将主力撤退到蚌埠。

而此时整个徐州城都知道了撤退的消息,负责殿后的李弥没和杜聿明打招呼,带着自己的军队先跑了,并且爆炸队摧毁了桥梁,导致所有人都知道国军要撤退了。关键就是杜聿明从哪里撤退。杜聿明本来可以撤退,蒋介石又让杜聿明解救黄维兵团,导致其被合围。

第二阶段以黄维兵团被全歼,李延年、刘汝明兵团溃退而结束。中央为了避免蒋介石调傅作义南下,提出先不打杜聿明,然后围歼杜聿明。

平津战役

当时美国对蒋介石失去信心,转而扶持地方实力派来维护自己的利益。司徒雷登与“华北王”傅作义商谈,派海军停在青岛,接应傅作义。
傅作义想在蒋介石、美国、中共之间斡旋。傅作义的女儿傅冬菊和其丈夫周毅都是共产党。傅作义想缓兵之计,巩固防线。

傅作义三条路:西撤绥远,但是那里物资匮乏,难以长久。东撤塘沽,准备海运南撤。或者固守北平。

西边是自己的嫡系部队,东部是蒋系部队,王牌35军机动部队。

主席认为切断傅作义回到绥远是重点,而重点就是平张线上的张家口。华北三兵团包围张家口,平津战役开始。杨成武、李天焕是华北三兵团司令和政委。由于傅作义不知道东野入关,决定派35军(军长郭景云)支援张家口。后来,东野(守塔山的程子华)占领密云,引起傅作义的警觉,让35军撤回北平。
35军被拖延一段时间,

由于三个兵团配合不利,没有堵住35军撤回北平的铁路。而且正是东北先遣部队攻占密云才引起傅作义警觉,主席很生气。

所以堵住35军的只有一个12旅,且背后还有傅作义派去接应的104军。南部的杨得志(罗瑞卿)主力要迅速支援上来。
华北二兵团克服困难,六昼夜急行军达到新保安地区,阻挡了35军撤回北平。而且104军也被切断了退路,被解放军歼灭。

此时蒋介石让傅作义经塘沽南撤。中央指示两个星期不进攻张家口和新保安,一方面拉拢傅作义,一方面给东北野战军入关争取时间,切断傅作义海路南撤的计划。东北野战军走山海关捷径直插天津、塘沽。

傅作义心存幻想,想三分天下。主席决定先吃掉35军。在新保安歼灭35军。

然后攻占了张家口,切断了傅作义向西撤退道路。

傅作义派出周北峰,张东荪作为谈判代表,中央派出林彪、罗荣桓、聂荣臻。傅作义提出军队出城整编,中共要求五天之内做出决定。

军委决定先打塘沽,再打天津,切断傅作义海上逃跑路线。纵队司令认为先打天津,再打塘沽。老蒋令陈长捷放弃天津,退守塘沽。陈长捷觉得对不起傅作义,没有答应。

刘亚楼攻击天津。迷惑敌人,攻击方向是城北。从东西进攻,在金汤桥对天津南北拦腰截断。29小时解放天津。

在东京铁塔 第一次眺望
看灯火模仿 坠落的星光
我终于到达 但却更悲伤
一个人完成 我们的梦想
你总说 时间还很多 你可以等我
以前我不懂得 未必明天 就有以后

结合电影《东京塔》:我从阿姨那儿得知“妈得了癌症,住院去做手术。”手术成功了,不过妈还没痊愈。只有持续用药控制癌细胞。尽管如此妈还是留在那个萧条的乡下打算工作着。为了回避她我到了东京。从十五岁离开她之后又过了十五年,我和妈在东京的杂居大楼,又开始二人生活。妈拿来世世代代继承的米糠,我像从前一样地每天吃着妈煮的饭。不久我的女友和朋友、同事等,为了吃我老妈亲手煮的菜而聚集到我家来。自从来了东京第一次才觉得每天是幸福快乐的。
2001年4月1日,樱花盛开的季节却飘起了雪花。透过医院的玻璃窗,我和妈妈遥望着东京塔。

没看你脸上 张扬过哀伤
那是种多么 寂寞的倔强
你拆了城墙 让我去流浪
在原地等我 把自己捆绑
你没说 你也会软弱 需要依赖我
我就装不晓得 自由移动 自我地过

我发誓不再说谎了 多爱你就会抱你多紧的
我的微笑都假了 灵魂像飘浮着 你在就好了
我发誓不让你等候 陪你做想做的无论什么
我越来越像贝壳 怕心被人触碰 你回来那就好了
能重来那就好了

歌词以“在东京铁塔,第一次眺望……”开头,正是因为原小说主角因父母离异,自小和母亲相依为命,过着困顿生活,但母亲的爱始终不虞匮乏。长大后主角辗转到东京发展小有成绩,约定跟母亲要一起到她向往的东京铁塔一游,但总因自己的各种理由,迟迟未能实现。直到母亲因病过世,主角抱着母亲的骨灰罐登上东京铁塔,才痛哭自己陪母亲的时间太少。

RDF、RDFS、OWL

RDF

Example3 Turtle:

@prefix person: http://www.kg.com/person/ .
@prefix place: http://www.kg.com/place/ .
@prefix : http://www.kg.com/ontology/ .

person:1 :chineseName “罗纳尔多·路易斯·纳萨里奥·德·利马”^^string;
:career “足球运动员”^^string;
:fullName “Ronaldo Luís Nazário de Lima”^^string;
:birthDate “1976-09-18”^^date;
:height “180”^^int;
:weight “98”^^int;
:nationality “巴西”^^string;
:hasBirthPlace place:10086.
place:10086 :address “里约热内卢”^^string;
:coordinate “-22.908333, -43.196389”^^string.

即,将一个实体用一个句子表示(这里的句子指的是一个英文句号“.”)而不是多个句子,属性间用分号隔开。

RDF的表达能力有限,无法区分类和对象,也无法定义和描述类的关系/属性。我的理解是,RDF是对具体事物的描述,缺乏抽象能力,无法对同一个类别的事物进行定义和描述。就以罗纳尔多这个知识图为例,RDF能够表达罗纳尔多和里约热内卢这两个实体具有哪些属性,以及它们之间的关系。但如果我们想定义罗纳尔多是人,里约热内卢是地点,并且人具有哪些属性,地点具有哪些属性,人和地点之间存在哪些关系,这个时候RDF就表示无能为力了。

RDFS和OWL这两种技术或者说模式语言/本体语言(schema/ontology language)解决了RDF表达能力有限的困境。

RDFS

RDFS/OWL本质上是一些预定义词汇(vocabulary)构成的集合,用于对RDF进行类似的类定义及其属性的定义。

我们这里只介绍RDFS几个比较重要,常用的词汇:

  1. rdfs:Class. 用于定义类。
  2. rdfs:domain. 用于表示该属性属于哪个类别。
  3. rdfs:range. 用于描述该属性的取值类型。
  4. rdfs:subClassOf. 用于描述该类的父类。比如,我们可以定义一个运动员类,声明该类是人的子类。
  5. rdfs:subProperty. 用于描述该属性的父属性。比如,我们可以定义一个名称属性,声明中文名称和全名是名称的子类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix : <http://www.kg.com/ontology/> .

这里我们用词汇rdfs:Class定义了“人”和“地点”这两个类。
:Person rdf:type rdfs:Class.
:Place rdf:type rdfs:Class.
rdfs当中不区分数据属性和对象属性,词汇rdf:Property定义了属性,即RDF的“边”。
:chineseName rdf:type rdf:Property;
rdfs:domain :Person;
rdfs:range xsd:string .

:career rdf:type rdf:Property;
rdfs:domain :Person;
rdfs:range xsd:string .

:fullName rdf:type rdf:Property;
rdfs:domain :Person;
rdfs:range xsd:string .

OWL

上面我们提到,RDFS本质上是RDF词汇的一个扩展。后来人们发现RDFS的表达能力还是相当有限,因此提出了OWL。我们也可以把OWL当做是RDFS的一个扩展,其添加了额外的预定义词汇。OWL,即“Web Ontology Language”,语义网技术栈的核心之一。OWL有两个主要的功能:1. 提供快速、灵活的数据建模能力。2. 高效的自动推理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix : <http://www.kg.com/ontology/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .

这里我们用词汇owl:Class定义了“人”和“地点”这两个类。
:Person rdf:type owl:Class.
:Place rdf:type owl:Class.

owl区分数据属性和对象属性(对象属性表示实体和实体之间的关系)。词汇owl:DatatypeProperty定义了数据属性,owl:ObjectProperty定义了对象属性。
:chineseName rdf:type owl:DatatypeProperty;
rdfs:domain :Person;
rdfs:range xsd:string .

:career rdf:type owl:DatatypeProperty;
rdfs:domain :Person;
rdfs:range xsd:string .

:fullName rdf:type owl:DatatypeProperty;
rdfs:domain :Person;
rdfs:range xsd:string .

描述属性特征的词汇

  1. owl:TransitiveProperty. 表示该属性具有传递性质。例如,我们定义“位于”是具有传递性的属性,若A位于B,B位于C,那么A肯定位于C。
  2. owl:SymmetricProperty. 表示该属性具有对称性。例如,我们定义“认识”是具有对称性的属性,若A认识B,那么B肯定认识A。
  3. owl:FunctionalProperty表示该属性取值的唯一性。例如,我们定义“母亲”是具有唯一性的属性,若A的母亲是B,在其他地方我们得知A的母亲是C,那么B和C指的是同一个人。
  4. owl:inverseOf. 定义某个属性的相反关系。例如,定义“父母”的相反关系是“子女”,若A是B的父母,那么B肯定是A的子女。

本体映射词汇(Ontology Mapping)

  1. owl:equivalentClass. 表示某个类和另一个类是相同的。
  2. owl:equivalentProperty. 表示某个属性和另一个属性是相同的。
  3. owl:sameAs. 表示两个实体是同一个实体。

本体映射主要用在融合多个独立的Ontology(Schema)。举个例子,张三自己构建了一个本体结构,其中定义了Person这样一个类来表示人;李四则在自己构建的本体中定义Human这个类来表示人。当我们融合这两个本体的时候,就可以用到OWL的本体映射词汇。

推理方面的能力:基于本体的推理和基于规则的推理
如果我们用inversOf来表示hasParent和hasChild互为逆关系,上面的数据可以表示为:
绿色的关系表示是我们RDF数据中真实存在的,红色的关系是推理得到的。

数据准备和实体建模

本实例数据获取方法:以周星驰为初始入口,获取其出演的所有电影;再获取这些电影的所有参演演员;最后获取所有参演演员所出演的全部电影。经过去重处理,我们得到了505个演员的基本信息和4518部电影的基本信息。数据保存在mysql中,其ER图如下:

protege字体调大,File-Perference-Renderer-font size即可。
首先填写本体资源的IRI。

然后创建三个类,分别为Genre、Movie、Person

切换到Object Properties,在此建立三个类之间的关系,”hasActedIn”表示某人参演了某电影,因此我们在右下方的3号矩形框中定义该属性的”domain”是人,4号框定义”range”是电影。这个很好理解,”domain”表示该属性是属于哪个类的,”range”表示该属性的取值范围。2号框表示该属性的逆属性是”hasActor”,即,有了推理机,尽管我们的RDF数据只保存了A出演了B,我们在查询的时候也能得到B的演员有A。

最后,我们切换到”Data properties”,我们在该界面创建类的属性,即,数据属性。其定义方法和对象属性类似,除了没有这么丰富的描述属性特性的词汇。其实不难理解,这些描述特性的词汇是传递、对称、反对称、自反等,表明其必定有指向其他资源或自身的边,而我们之前提到过,数据属性相当于树的叶子节点,只有入度,而没有出度。

然后保存成为了owl文件,内容即为之前设置的class、object property、Data property三部分。

关系数据库到RDF

从关系数据库映射到RDF的两个标准

  • direct mapping
    1.数据库的表作为本体中的类(Class)。比如我们在mysql中保存的数据,一共有5张表。那么通过映射后,我们的本体就有5个类了,而不是我们自己定义的三个类。2. 表的列作为属性(Property)。3. 表的行作为实例/资源。4. 表的单元格值为字面量5. 如果单元格所在的列是外键,那么其值为IRI,或者说实体/资源。

  • R2RML
    generate-mapping -u root -o kg_demo_movie_mapping.ttl jdbc:mysql:///kg_demo_movie
    .\d2r-server lsy.ttl
    生成一个mapping的ttl文件,

把每个表映射成为一个类,每一行是一个资源,每一列就是资源的属性。

http://www.pizza.com/ontologies/pizza.owl
Functional Properties:一一映射,一个输入对应的输出是相同的:
比如A的生母是B,也是C,生母关系具有函数性,那么B和C是同一个人。
反函数性可以一对多。

接下来,把默认的映射词汇改为我们本体中的词汇即可。在处理外键的时候要注意当前编辑的属性的domain和range,belongsToClassMap是domain,refersToClassMap是range。
1、三个类中,genre__label和genre_genre_id都去掉了
2、vocab:xxxx 换成了本体构建时候的术语
第一点:我们不需要这两个属性,对我们的系统或者后续应用没有什么帮助。第二点:vocab:xxxx是默认mapping文件定义的转换规则,就是把数据库的字段名和表名直接当成本体。因此要换成我们自己定义的本体。
d2rq:property vocab:person_to_movie; ——> d2rq:property :hasActedIn;
d2rq:property vocab:person_person_birth_place; ——-> d2rq:property :personBirthPlace;

.\dump-rdf.bat -o kg_demo_movie.nt .\kg_demo_movie_mapping.ttl
将数据转为RDF。

这样就利用D2RQ完成了从MySQL数据表到RDF格式数据的转换。

RDF查询语言SPARQL

查询实例:

周星驰出演了哪些电影:
PREFIX : http://www.kgdemo.com#
PREFIX rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
PREFIX owl: http://www.w3.org/2002/07/owl#
PREFIX xsd:
PREFIX vocab: http://localhost:2020/resource/vocab/
PREFIX rdfs: http://www.w3.org/2000/01/rdf-schema#
PREFIX map: http://localhost:2020/resource/#
PREFIX db: http://localhost:2020/resource/

SELECT ?n WHERE {
?s rdf:type :Person.
?s :personName ‘周星驰’.
?s :hasActedIn ?o.
?o :movieTitle ?n
}

英雄这部电影有哪些演员参演?:
SELECT ?n WHERE {
?s rdf:type :Movie.
?s :movieTitle ‘英雄’.
?a :hasActedIn ?s.
?a :personName ?n
}

D2RQ来实现查询SPRAQL

D2RQ以虚拟的RDF的方式来访问关系数据库中的数据,即我们不需要显式地把数据转为RDF形式。通过默认,或者自己定义的mapping文件,我们可以用查询RDF数据的方式来查询关系数据库中的数据。换个说法,D2RQ把SPARQL查询,按照mapping文件,翻译成SQL语句完成最终的查询,然后把结果返回给用户。

进入d2rq目录,使用下面的命令启动D2R Server:

d2r-server.bat kg_demo_movie_mapping.ttl
默认端口是2020,在浏览器输入“http://localhost:2020/”,可以看到如下界面:

点击红色方框2中的链接,进入endpoint.

除了利用浏览器,也可以使用python进行交互。见代码中的MyTest文件。

Apache jena SPARQL endpoint及推理

本次实践我们会用到的组件有:TDB、rule reasoner和Fuseki。

  1. TDB是Jena用于存储RDF的组件,是属于存储层面的技术。在单机情况下,它能够提供非常高的RDF存储性能。目前TDB的最新版本是TDB2,且与TDB1不兼容。
  2. Jena提供了RDFS、OWL和通用规则推理机。其实Jena的RDFS和OWL推理机也是通过Jena自身的通用规则推理机实现的
  3. Fuseki是Jena提供的SPARQL服务器,也就是SPARQL endpoint。其提供了四种运行模式:单机运行、作为系统的一个服务运行、作为web应用运行或者作为一个嵌入式服务器运行。

创建一个目录(我这里命名为“tdb”)用于存放tdb数据。进入“apache-jena-X.X.X”文件夹的bat目录,可以看到很多批处理文件,我们使用“tdbloader.bat”将之前我们的RDF数据以TDB的方式存储。命令如下:

.\tdbloader.bat —loc=”D:\apache jena\tdb” “D:\d2rq\kg_demo_movie.nt”

“—loc”指定tdb存储的位置,即刚才我们创建的文件夹;第二个参数是由Mysql数据转换得到的RDF数据。

进入入“apache-jena-fuseki-X.X.X”文件夹,运行“fuseki-server.bat”,然后退出。程序会为我们在当前目录自动创建“run”文件夹。将我们的本体文件“ontology.owl”移动到“run”文件夹下的“databases”文件夹中,并将“owl”后缀名改为“ttl”。在“run”文件夹下的“configuration”中,我们创建名为“fuseki_conf.ttl”的文本文件(取名没有要求),加入如下内容:

报错的话,进入到D:\MMKG\env\apache-jena-3.5.0\tdb目录下,将前缀为prefix的文件全部删除,再次运行即可。
再次运行“fuseki-server.bat”,如果出现如下界面表示运行成功:

进入localhost:3030
PREFIX : http://www.kgdemo.com#
PREFIX rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
PREFIX rdfs: http://www.w3.org/2000/01/rdf-schema#

SELECT * WHERE {
?x :movieTitle ‘功夫’.
?x ?p ?o.
}

进行如下查询,可以得到hasActor属性,电影的“hasActor”属性是通过OWL推理机得到的,即我们原本的RDF数据里面是没有的。

在“databases”文件夹下新建一个文本文件“rules.ttl”,填入如下内容:

1
2
3
4
5
6
7
8
@prefix : <http://www.kgdemo.com#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xsd: <XML Schema> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

[ruleComedian: (?p :hasActedIn ?m) (?m :hasGenre ?g) (?g :genreName '喜剧') -> (?p rdf:type :Comedian)]
[ruleInverse: (?p :hasActedIn ?m) -> (?m :hasActor ?p)]

我们定义了一个名为“ruleComedian”的规则,它的意思是:如果有一个演员,出演了一部喜剧电影,那么他就是一位喜剧演员。修改配置文件“fuseki_conf.ttl”:

demo实例

基本流程

此demo是利用正则表达式来做语义解析。我们需要第三方库来完成初步的自然语言处理(分词、实体识别),然后利用支持词级别正则匹配的库来完成后续的语义匹配。

分词和实体识别(人名和电影名)我们用jieba来完成。jieba是一个轻量级的中文分词工具,有多种语言的实现版本。对于分词,在实验环境中,jieba还是勉强能用。在我们这个demo当中,有些经常会被使用的词语并不能被正确切分。比如:“喜剧电影”、“恐怖电影”、“科幻电影”、“喜剧演员”、“出生日期”等,在分词的时候,jieba把它们当作一个词来处理,我们需要手动调整词语的频率使得“喜剧电影”能被切分为“喜剧”和“电影”。至于实体识别,jieba对于人名的识别精度尚可接受,但是电影名称的识别精度太低以至于完全不可用。因此,我们直接把数据库中的人名和电影名导出,作为外部词典;使用jieba的时候加载外部词典,这样就能解决实体识别的问题。

将自然语言转为以词为基础的基本单位后,我们使用REfO(Regular Expressions for Objects)来完成语义匹配。具体实现请参考OpenKG的demo或者本demo的代码。

匹配成功后,得到其对应的我们预先编写的SPARQL模板,再向Fuseki服务器发送查询,最后将结果打印出来。

  • “crawler”文件夹包含的是我们从”The Movie DB”获取数据的脚本。
  • “KB_query”文件夹包含的是完成整个问答demo流程所需要的脚本。
  • “external_dict”包含的是人名和电影名两个外部词典。csv文件是从mysql-workbench导出的,按照jieba外部词典的格式,我们将csv转为对应的txt。
  • “word_tagging”,定义Word类的结构(即我们在REfO中使用的对象);定义”Tagger”类来初始化词典,并实现自然语言到Word对象的方法。
  • “jena_sparql_endpoint”,用于完成与Fuseki的交互。
  • “question2sparql”,将自然语言转为对应的SPARQL查询。
  • “question_temp”,定义SPARQL模板和匹配规则。

“query_main”,main函数。在运行”query_main”之前,读者需要启动Fuseki服务,具体方法请参考上一篇文章。

streamlit run streamlit_app.py —server.enableCORS=true
终端输入可在浏览器中使用。

重载和重写

分布式事务

什么是分布式事务

指事务的参与者、支持事务的服务器、资源服务器、事务管理器分别位于不同的分布式系统的不同节点之上。简单说,就是分布式系统中的事务,它的存在是为了保证不同的数据库节点的数据一致性。

CAP理论

  • Consistency:数据在多个副本之间保持一致性。例如一个数据在某个分区节点更新后,在其他分区节点读出来的数据也是更新之后的数据。
  • Availability:系统提供的服务必须一直处于可用的状态。对于用户的操作请求总是能在有限的时间内返回结果。
  • Partition tolerance分布式系统在遇到任何网络分区故障时,仍然能保证对外提供满足一致性和可用性的服务。

BASE理论

是对于AP的一个扩展,牺牲一致性换取系统的可用性分区容错性。BASE是Basically Available、soft state、eventually consistent三个短语的缩写。

  • 基本可用指,通过支持局部故障而不是系统全局故障来实现
  • soft state表示状态可以有一段时间不同步
  • 最终一致,不要求实时保持强一致

redis

redis登录
auth “password”
密码可以在安装目录下的redis.windows.conf里搜索foo得到

redis类型

string类型的常用命令,
set,get,strlen,exists,dect,incr,setex
应用场景:用在需要计数的场景,比如用户的访问次数,热点文章的点赞转发数

list常⽤命令: rpush,lpop,lpush,rpop,lrangellen 等。
应⽤场景: 发布与订阅或者说消息队列、慢查询。

redis为什么采用单线程

一开始使用单线程,在4.0版本后抛弃了单线程,其中的原因是什么。
因为它是一个内存服务器,处理很多来自外部的网络请求,使用I/O多路复用机制同时监听多个文件描述符的可读和可写状态。一旦收到网络请求就会在内存当中快速处理,由于操作是纯内存的,所以处理速度很快。

  • 为什么redis服务使用单线程模型处理绝大多数的网络请求
  • 为什么redis服务增加多个非阻塞的删除操作,例如UNLINK,FLUSHALL ASYNC,FLUSHDB ASYNC。

使用单线程的好处:

  1. 更好的可维护性,方便开发和调试(多线程需要加锁、同步等很麻烦)
  2. 即使单线程,也能并发地处理客户端的请求(使用I/O多路复用,并发处理来自客户端的多个连接)
  3. redis服务绝大多数操作的瓶颈不是CPU(多线程的优点是充分利用CPU的计算资源来并发地执行不同的任务,但是redis不是CPU密集型的服务,服务的瓶颈在于网络传输的延时和等待客户端的数据传输,即网络I/O)

为什么又引用多线程:
对于 Redis 中的一些超大键值对,几十 MB 或者几百 MB 的数据并不能在几毫秒的时间内处理完,Redis 可能会需要在释放内存空间上消耗较多的时间,这些操作就会阻塞待处理的任务。然而释放内存空间的工作其实可以由后台线程异步进行处理,这也就是 UNLINK 命令的实现原理,它只会将键从元数据中删除,真正的删除操作会在后台异步执行。

redis给缓存数据设置过期时间

因为内存是有限的,如果缓存中的所有数据一直存在,分分钟out of memory。redis自带了给缓存数据设置过期时间的功能。
exp key 60 #60s后过期
setex key 60 value #设置数据60s之后过期
ttl key #查看数据还有多久过期

除了字符串有独有的设置过期的命令:setex,其余要依靠expire命令来设置过期时间,persist可以移除一个键的过期时间。

而且很多时候业务场景要求某个数据只在某一个时间段内存在,比如短信验证码只在1分钟内生效,用户登录的token只在1天内有效。

过期的数据如何删除

  1. 惰性删除:只有在取出key的时候才检查,对CPU友好,但是会造成太多过期key没有被删除
  2. 定期删除:每隔一段时间,抽取一批key执行删除过期key操作。并且,redis底层会通过限定删除操作执行的时长和频率来减少删除操作对CPU的影响。

定期删除对内存更加友好,惰性删除对CPU友好,redis采用的是定期+惰性。
即使如此,还是会有大量key过期堆积在内存,导致out of memory。还要内存淘汰机制。
将最近不常使用的key删除

redis持久化(怎么保证redis挂掉之后再重启,数据能够恢复)

一种方式是快照,(snapshotting ,RDB),另一种方式的只追加文件,(append-only file AOF)

创建快照获得存储在内容中数据在某个时间点的副本,对快照备份可以复制到其他服务器,也可以保存本地,下次重启时使用。

save 900 1 #在900秒(15分钟)之后,如果⾄少有1个key发⽣变化,Redis就会⾃动触发
BGSAVE命令创建快照。

与快照持久化相⽐,AOF 持久化 的实时性更好,因此已成为主流的持久化⽅案。默认情况下
Redis 没有开启 AOF(append only file)⽅式的持久化,可以通过 appendonly 参数开启

开启 AOF 持久化后每执⾏⼀条会更改 Redis 中的数据的命令,Redis 就会将该命令写⼊硬盘中
的 AOF ⽂件。AOF ⽂件的保存位置和 RDB ⽂件的位置相同,都是通过 dir 参数设置的,默认的
⽂件名是 appendonly.aof。

多线程

同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈
Java程序天生是多线程的,一个Java程序的运行是main线程和多个其他线程同时运行。

[5] Attach Listener //添加事件
[4] Signal Dispatcher // 分发处理给 JVM 信号的线程
[3] Finalizer //调⽤对象 finalize ⽅法的线程
[2] Reference Handler //清除 reference 线程
[1] main //main 线程,程序⼊⼝

程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时通过改变计数器的值来选取下一条要执行的字节码指令。生命周期随着线程的创建而创建,结束而结束。

虚拟机栈:主要是局部变量表,

线程安全

和线程同步是一个东西,当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的线程不能再对他进行操作了,必须等到这次访问结束以后才能对这个线程安全的方法进行访问。
代码所在的进程中有多个线程同时运行,如果每次运行的结果和单线程运行的结果是一致的,就是线程安全。多个线程之间的切换不会导致程序运行结果的二义性,即不需要考虑同步的问题。
同步:线程A更改了变量,更改后的结果要同步给线程B才行。

idea快捷键

  1. var声明
    20.var/ “jack”.var/ new Person().var

  2. .nn .null
    判空,自动添加一个if判断

  3. for遍历
    list.for list.fori

  4. .if .return .cast

Ctrl+Y:删除光标所在行或选中内容
Ctrl+D:复制光标所在行或选中内容,插入到光标下面
Ctrl+N:查找类或者文件

github搜索技巧

在pycharm的Project下的Python Interpreter下更改环境

github中下载单个文件,点击进去,点击raw,然后ctrl+s即可。

chorm安装插件GitZip for github可以下载单个文件夹或文件。

jupyter快捷键

关于VO(view object)和DTO(data transfer object)

entity里的每一个字段和数据库相对应。
vo里每个字段和HTML页面对应
dto是用来转换从entity到vo,或者vo到entity中间的东西。

举个例子:

你的html页面上有三个字段,name,pass,age

你的数据库表里,有两个字段,name,pass , 注意没有 age。

而你的 vo 里,就应该有下面三个成员变量 ,因为对应 html 页面上三个字段 。

1
2
3
private string name;
private string pass;
private string age;

这个时候,你的 entity 里,就应该有两个成员变量 ,因为对应数据库表中的 2 个字段 。
1
2
private string name;
private string pass;

到了这里,好了,业务经理让你做这样一个业务“年龄大于 20 的才能存入数据库,这个时候,你就要用到 dto 了,

1)你要先从页面上拿到 vo,然后判断 vo 中的 age 是不是大于 20。

2)如果大于 20,就把 vo 中的 name 和 pass 拿出来,放到 dto 中。

3)然后在把 dto 中的 name 和 pass 原封不动的给 entity,然后根据 entity 的值,在传入数据库。

这就是他们三个的区别。

“F:\Nodejs\node_global\node_modules\hexo\README.md”

  1. 出生

    科西嘉岛是地中海的要地,位于意大利西部。1769年出生,拿破仑意大利语为“荒野雄狮”。其父亲本来是意大利贵族,被法国占领后,效忠法国。路易十五也承认他们为法国贵族。其父亲在他不到十岁时,送到法国欧坦的奥顿教会学校学法语。拿破仑仅学习半年,在父亲安排下进入布里埃纳军校学习,由于个子矮小、身份原因、法语不够好,经常受欺负。拿科西嘉的战败嘲笑他。他认为是法国侵占了他的故乡。

1784年拿破仑毕业,进入巴黎军官学校学习炮兵。这几年,他开始阅读法国名家的著作,开始热爱了法兰西。1785年父亲去世,家庭失去了收入来源。拿破仑不得不提前毕业,进入部队。1789年法国大革命,拿破仑返回家乡,保利返回科西嘉岛,想让科西嘉独立。拿破仑不同意,认为应该归顺法国。与保利闹掰,回到法国。1792年成立法兰西第一共和国,第二年将路易十六杀头。此举引发欧洲各国的恐慌,为了维护封建专制的地位和遏制法国扩张,组成反法同盟。

1793年,国内为了反抗雅各宾派专政,马赛、土伦等几座南方沿海城市集体叛乱,邀请英国和西班牙军队入侵。拿破仑取得土伦的军队指挥权,最终获胜。被罗伯斯比尔提升为炮兵准将。
1794年,雅各宾派被推翻,罗伯斯比尔被杀头,拿破仑被逮捕调查。由于证据不足,拿破仑出狱。
1795年,拿破仑被任命,镇压旺代的起义,但是被编入步兵,而且拿破仑不愿打自己人,拒绝出任。由于热月党统治残暴,巴黎地区落入起义军手中。拿破仑被任命镇压起义军,拿破仑成为国内防军总司令。

约瑟芬受到拿破仑的追求,两人订婚。

少时性格孤僻,一个人在家中看书。如果有人欺负他,一定会大打出手。父亲有贵族身份,进入好的学校学习。1789年法国大革命,将皇帝路易十六杀头,欧洲几个国家的皇帝联合反法,拿破仑从军,由于法国军队节节败退,法国出现内乱,土伦是法国南部的重要港口,一旦失守,英国可以从此登陆法国,拿破仑当上了炮兵的指挥官,收复了土伦港口。

拿破仑打败了意大利、奥地利,击败了第一次反法同盟,保卫了法国的革命果实。

  1. 称帝
    由于法国是共和国,到处帮助别的国家革命,宣传自己的先进制度。拿破仑组建一个强大的舰队,英国试图阻止,但被狂风卷走搁浅。拿破仑去远征埃及,纳尔逊封锁港口,拿破仑写给老婆的信被英军截获,得知其老婆出轨。1799年拿破仑放弃埃及军队,一个人偷偷返回巴黎,发动雾月政变,法国从共和国变成了帝国,本来该由教皇戴皇冠,但是拿破仑厌恶教皇。
    1805年,拿破仑把自己加冕为意大利国王,侵犯了奥地利的利益,奥地利联合俄国反法,奥斯特里茨之战,拿破仑派人求和,让沙皇膨胀最终获胜。
  1. 远征俄罗斯
    1807年,西班牙内乱,影响法国的利益,拿破仑拥立自己哥哥当西班牙国王,西班牙反对,英国联合西班牙反法,奥地利从东线攻打法国,拿破仑从西边撤退打败奥地利,签订《维也纳合约》,法国第一帝国达到了鼎盛。

1812年拿破仑远征俄罗斯,到处都是荒芜,得不到补给,9月拿破仑到达莫斯科郊外,
遭遇顽强抵抗,攻入莫斯科,城市已经被火烧。

俄国在拿破仑返回途中埋伏,并且被寒冬击败。此时,奥地利和普鲁士对拿破仑出兵,击败三国联军,英国人在西线攻打法国。
1814年各国联军进入巴黎,拿破仑被迫退位,流放厄尔巴岛,拿破仑之后逃跑,登录法国,法国皇帝派军攻打拿破仑,却倒戈,拿破仑再次称帝。

再次反法同盟会战,滑铁卢会战。拿破仑流放到圣赫那拉岛,