用于将用于自动化目的的数据模型变换成目标本体的方法与流程

文档序号:25542628发布日期:2021-06-18 20:39阅读:177来源:国知局
用于将用于自动化目的的数据模型变换成目标本体的方法与流程

本实施例涉及一种用于将用于自动化目的的数据模型变换成本体的方法。更具体地,本实施例涉及一种用于将专用于自动化目的的语义丰富且基于图的(graph-based)数据模型变换成目标本体的方法。



背景技术:

过去的工业自动化系统组件在传统上已经使用标准工业协议通过专用网络而互连,以用于访问和数据交换。当前和未来的自动化系统的发展已经将相当多的重点放在交换语义丰富的信息上,旨在实现灵活的制造场景。

为了克服工业制造系统中仍然存在的低级别(low-level)信号通信,已经提出了一种名为opcua的协议,以用于将现场级别通信增强到语义级别。opcua(开放平台通信统一架构)是opc基金会的工业标准协议,该协议用于特别是在过程自动化中以互换工业数据为目的的独立于制造商的通信。

opcua的数据模型的特征是语义丰富且基于图的数据结构,该数据结构专用于自动化目的。然而,opcua而是定义了规范文档内用于表达语义描述的概念,这意味着缺乏形式语义表示。因此,opcua的使用由于其缺乏形式语义表示而遭受显著缺陷:

-作为第一个缺陷,不能够借助于计算机系统来完全自动验证opcua的数据模型,这是由于不存在将允许由验证工具进行自动处理的语义描述的规则集。在没有形式定义的情况下无法解决的另一个问题是对核心opcua标准本身的核实,该标准本身也可能包含不一致的陈述(statement)。

-作为第二个缺陷,opcua数据模型内的查询是复杂的(intricate)。尽管opcua定义了用于访问数据模型的查询语言,但是迄今为止,还不存在用于实现查询请求的任何框架,尤其是由于为了查询opcua的数据模型内分散(scatter)的语义描述所负担的高复杂性。

-作为第三个缺陷,opcua中的形式语义的缺乏阻碍了针对如技能匹配(skill-matching)、数据挖掘、监测等任务的分析过程。

因此,本领域中存在如下需要:即,便于在语义丰富的基于图的数据模型(特别是opcua)内进行验证、分析或查询,同时解决在这种数据模型内所分散的语义描述的复杂性。



技术实现要素:

根据本发明,在解决所考虑的数据模型的现有问题时的一个初步考虑是:该模型内的语义的分散性质必须被更改,从而有利于形式语义表示。

本文中的实施例通常涉及将数据模型变换成本体,该本体被理解为术语和概念以及这些概念之间的关系的形式语义表示。本体容易地提供用于使用适配于本体的形式表示的精密(sophisticated)标准工具来验证、查询和分析数据模型的期望能力。

在一个实施例中,提出了一种用于将语义丰富且基于图的数据模型变换成目标本体的计算机实现的方法,其中由第一存储器单元来提供数据模型的至少一个层。数据模型包括由属性来描述并且通过引用而互连的多个节点。通过第一步骤,从数据模型的所述节点中检索标识。由此,由符合rest(表示性状态转移)规则集的uri或唯一资源标识符来表达(即,替换或修改)每个标识。随后地或同时地,检索将一个或多个节点互连的一个或多个引用的语义描述。由要产生的目标本体中的至少一个谓词和/或至少一个类来表达(即,替换或修改)这些语义描述。最终,通过语义本体语言来构造目标本体,并且将目标本体输出到三元组存储(triplestore)。

根据另一个实施例,提供了一种变换单元,该变换单元包括处理器、以及其上存储有计算机可执行程序代码的数据存储设备。数据存储设备可以在处理器内或者在处理器外部来实现。

根据进一步的实施例,提供了一种其上存储有计算机可执行程序代码的非暂时性计算机可读存储介质。

附图说明

从结合附图取得的对优选实施例的以下描述中,本实施例的目的以及进一步的优点将变得更加明显且容易领会,在附图中,该图示出了根据opcua的模块化结构的分层架构框架。

具体实施方式

现在转到该图,该图示出了根据opcua的模块化结构的分层架构框架。opcua框架提供了如下分层结构:

-在元层0上,基本实体(例如,节点类、属性、引用等)由opcua元层oml来定义。

-最一般的opcua核心模型或opcua基层obm由opc基金会自己来提供。核心模型obm包括基层1上的基本变量类型、服务器类型、工程单位等的规范。

-在上面的伴随层(companionlayer)2中,至少一个所谓的opcua伴随规范cs1、cs2用于定义领域特定的模型或模式(schema),该领域特定的模型或模式扩展了opcua模型。较低的伴随规范cs1可以包括拓扑元素类型定义;上方的伴随规范cs2可以包括流类型定义,或者更具体地,包括cnc机器(计算机数控)的轴类型。

-上面的扩展层3托管着由oem(原始设备制造商)创造的oem特定的模式扩展,包括例如:包括设备类型描述的设备供应商信息模型dvi、包括机器类型描述的机器供应商信息模型mvi、以及包括过程类型或工厂元素类型的机器用户信息模型mui。

-最终,该分层模型的顶部上的实例层4包括设备/资产信息模型dim,即用于基于下面的层0、1、2、3中定义的模式来描述个体设备的配置和数据项的实例模型。

-垂直于层0、1、2、3、4的opcua信息建模oim遍及所有层0、1、2、3、4对该opcua数据模型中的一致性(consistency)进行符号化。信息模型的表达性通常从较低层向较高层增加。

在下面将进一步描述的实施例的预期中,用于将相应层0、1、2、3、4内的信息模型或数据模型变换成相应本体ont的变换过程trf可以有利地以类似模块化的方式来执行,如附图中所示的那样。

实施例有利地支持提供数据模型的一个或多个层,以便被变换成相应的本体ont。变换过程trf通过将相应层上的每一个模块变换成本体ont来对opcua信息模型或数据模型进行变换,这些本体ont以与相应opcua模块相同的方式而彼此导入。一旦该变换过程trf被执行,所得的本体ont就可以被用于验证、查询和分析目的。

出于验证目的,将作为基于图的数据模型的opcua图变换成基于rdf的目标本体,然后使用标准本体工具对该目标本体进行验证,而不是验证基于图的数据模型。在该验证步骤之后,有可能使用常规的推理机(reasoner)来检查目标本体的一致性,而无需用于实现验证算法的附加努力。这种方法还将支持通过用于构建目标本体的语义本体语言的声明性性质来进行自动规则更新。参考回到该图,该验证可以在基层1上进行以确保核心规范本身的一致性,在伴随层2上进行以用于对照核心规范来验证新开发的伴随规范,在扩展层3上进行以用于对照下层的方案来验证供应商特定的扩展,并且最后在实例层4上进行以用于对照给定模式来验证实例模型。为了能够完全覆盖所有opcua规则、以及还有可能由伴随规范添加的所有规则,可能有必要组合若干个不同的推理技术,例如owl(web本体语言)、shacl(形状约束语言)等。

出于查询目的,实施例有利地支持使用公共查询语言sparql(sparql协议和rdf查询语言)来提供对opcua数据模型的简单访问。为此,实施例确保目标本体内的rdf表示作为结果,该结果以形式方式来捕获opcua语义。查询通常发生在实例层上,以便找到用于其他应用(例如,监测、人机接口、维护……)的必要数据点。然而,查询也可以出于内省(introspection)目的而在扩展层3和伴随层2上使用,并且进一步为了验证而在基层1上使用。

为了支持分析,实施例有利地支持以形式方式获得对opcua伴随标准的语义的访问。形式访问使得能够实现如技能匹配、载入(onboarding)、监测等用例。这对于与伴随层2相结合的实例层4特别有用,其中伴随层2提供针对给定领域的标准化语义,并且由此实例层4提供由这些语义标记的具体值。基于伴随层2,语义互操作性可以通过针对给定领域的广泛接受的标准化词汇来实现。形式owl表示还可以用于将不同的opcua伴随规范互连,以表达来自不同领域的两个概念含义相同的事实(例如,温度),这在opcua本身中当前未被标准化。扩展层也可以用于分析,并且对于在没有opc基金会的形式标准化过程的情况下容易地将本体导入到opcua中来说尤其有用。本体的这种导入可以使用现有本体(如schema.org或语义传感器网络本体)来处理。

在下文中,现在进一步详细地公开了用于将相应层0、1、2、3、4内的数据模型变换成相应目标本体ont的变换过程trf。

根据实施例的第一步骤,检索upcua节点的标识或节点id,并且由符合rest(表示性状态转移)规则集的uri(唯一资源标识符)来表达每个标识。

在opcua数据模型中,地址空间中的每个实体是节点。为了唯一地标识节点,每个节点具有节点id,包括三个元素,即名称空间索引(namespaceindex)、标识符类型和标识符。

名称空间索引是由在线操作中的opcua服务器使用的索引(通常是数值)而不是名称空间标识符,以便加快数据的传递和处理。名称空间标识符标识了定义节点id的标识符的命名机构,例如opc基金会、其他标准主体和联盟、底层系统或本地服务器。名称空间索引与其相应的名称空间标识符或名称空间uri(统一资源标识)一起被存储在存储库中。opcua内的该存储库也被称为名称空间数组(array)。标识符类型定义了标识符的数据类型,例如数值、字符串等。标识符最终标识了opcua服务器的地址空间中的节点。

尽管opcua规范认可了系统范围且全局唯一的标识符(节点id),但是存在其中多于一个节点具有共同标识符(例如,显示名称(displayname)、描述)的情况。因此,标识的检索可以可选地伴随着每个opcua节点的浏览名称或»browsename«的检索,以便明确地(unambiguously)映射具有共同名称的不同语义。然而,一般而言,opcua允许多个节点共享相同的浏览名称。尽管根据opcua的浏览名称不能够用于在所有情况下都明确地标识节点——这是由于不同的节点可能具有相同的浏览名称——但是可以提供浏览名称的名称空间,以使得浏览名称在一些情况下在节点的上下文(例如,节点的一些性质)中是唯一的。

节点的示例性标识(基于节点id)被构造如下:

namespacestring/i=1:11111111111

其中»namespacestring(名称空间字符串)«是表达名称空间标识符的字符串。所述字符串是基于名称空间索引从名称空间数组中收集的,此处名称空间索引具有节点id的1(一)的数值。名称空间字符串(namespacestring)需要以斜杠或»/«来结束。节点id如下面进一步描述的那样而组成。名称空间索引i被设置为1,这是因为其是针对必须与该名称空间字符串相等的本地服务器的索引。例外是具有零或»0«的值的名称空间索引,这指示该节点是opcua基本模型obm的一部分。然而,仅在»namespacestring«等于名称空间数组的索引1的情况下允许省略对应的名称空间数组。

包括限定名称的节点的进一步示例性标识被构造如下:

namespacestring/qualifiedname.name

其中»qualifiedname(限定名称)«是具有两个部分的数据结构,这两个部分是:名称空间索引和名称。名称空间字符串基于名称空间数组的对应条目(例如http://opcfoundation.org/ua/servertype)

包括查询的节点的进一步示例性标识被构造如下:

<host>/i=1:11111111111/qualifiednamestringns=namespacestringarray

其中序列»ns=namespacestringarray«指定针对名称空间数组中的名称空间的查询。在这种情况下,名称空间字符串基于查询参数»ns=namespacestringarray«,其中查询参数中的第一个条目代表名称空间索引1。

如上所示的节点的这种opcua标识将由符合rest或表示性状态转移规则集的uri来表达。表示性状态转移或rest是一种软件架构风格,其定义了用于创建web服务的一组约束。rest的约束之一是uri的统一资源标识,例如根据互联网工程任务组(ietf)的建议rfc3986(»注解请求(requestsforcomments)«)。

根据rfc3986的uri的示例性通用示例被构造如下:

https://example.com:8042/over/therename=gear#shaft

其中序列»https«指定了方案,序列»example.com:8042«指定了权威机构(authority),序列»/over/there«指定了路径,序列»name=gear«指定了查询,并且序列»shaft«指定了片段(fragment)。

特定于根据rfc3986的uri的opcua竞赛(contest)的示例被构造如下:

https://example.com:8042/vendorspecific/v1.04/11111/i=111111111qkey=qvalue

其中,序列»https«指定了方案,序列»example.com:8042«指定了权威机构,序列»/vendorspecific«指定了路径前缀,序列»/v1.04«指定了通常由opc基金会设置的api(应用编程接口)的版本或apiversion。可选序列»/11111«指定了作为opcua服务器的性质值的uri版本或uriversion。包括后三个序列»/vendorspecific/v1.04/11111/i=111111111«的字符串被称为路径。最后,序列»qkey=qvalue«指定了针对键qkey内的查询值qvalue的查询。

为了标识这些序列,利用以下规则来应用解析器(parser):

1.查找查询分隔符(第一个“”),并且将uri拆分成路径和查询

2.拆分路径元素中的路径(分隔符“/”)

3.检查第一个路径元素是否是节点id(如果“=”存在,则为真)

a.如果“=”存在:

i.检查节点id类型(“=”左侧的第一个字符)

ii.解码在节点id类型标识符左侧的服务器索引(“=”左侧的第一个字符)

iii.拆分节点id值(“=”的右侧)

1.拆分名称空间中的节点id值(左侧)以及标识符(右侧)(分隔符=“:”);

2.基于节点id类型来解码标识符

b.如果不存在“=”:

i.拆分名称空间中的浏览名称(左侧)以及值(右侧)(分隔符=“:”)

ii.解码浏览名称的值部分

4.拆分名称空间中的浏览名称(左侧)以及值(右侧)(分隔符=“:”)

a.解码浏览名称的值部分

5.检查最后一个浏览名称是否是属性浏览名称

6.拆分查询参数(queryarg)

a.查找下一个“=”;左侧是键;

b.查找下一个“&”;左侧是值;

i.拆分数组元素(分隔符“,”)

1.解码每个元素。

尽管期望不仅推断机器可读的uri、而且还推断人类可读的uri(后者可以稍后用于方便的寻址),但是该目的基于如下假设:类型的浏览名称是唯一的。更具体地说,将不允许用相同的浏览名称来定义两个类型。然而,这种约束在opcua内通常不是必需的,并且不能够在每种情况下被保证。至少该唯一性被认为是良好的模型实践。

如果该假设不成立,则应使用节点id而不是浏览名称。进一步地,结构字段名称(structurefieldname)和实例声明浏览名称(instancedeclarationbrowsename)应当具有类似的限制。然而,在这种情况下,浏览名称可以被重复使用若干次,但是含义应当始终相同。例如,应当避免用浏览名称来定义两个实例声明:

http://mynamespace.org/sensorvalue

其中在一种情况下论述温度,并且在另一种情况下论述压力,而这些传感器值之间的差异仅能够由人类通过读取不同实例声明的不同描述属性来解释。

在这两种情况下,使用更具体的浏览名称是更适当的,例如

http://mynamespace.org/temperature

http://mynamespace.org/pressure

后备解决方案是:使用实例声明的节点id而不是浏览名称。一般而言,应当考虑针对重复使用的浏览名称的以下条件:

-描述名称(descriptionname)和显示名称属性是相同的。无论如何,这是生成器工具的默认检查。

-不同实例声明的语义是相同的。人类将会假设,两个实例声明论述相同的事物,例如,在其中描述名称或显示名称属性不同的情况下的温度值。

-只要浏览名称的语义仍然适用,就允许改变数据类型(datatype)、建模规则(modellingrule)、节点类(nodeclass)、类型定义(typedefinition)和引用类型(referencetype)。例如,在一种情况下,温度作为简单变量而暴露,其中在另一种情况下,使用了复杂变量。然而,如果这些概念必须改变,则通常应当考虑使用不同的浏览名称。

总之,用于检索节点id以及可选地检索浏览名称、并且由符合rest规则集的uri来表达这些的实施例的第一步骤简单地提供了由符合rest架构风格的web-客户端进行的可访问性。除此之外,以人类在字面上可读的形式提供了uri。当应用本体编辑器和知识管理系统工具(如sparql和protégé)时,这种可读性有利地改进了用户体验。

protégé是免费的开源本体,其特征是用于定义和修改本体的图形用户界面。protégé包括用于验证一致性以及用于基于本体的分析来推断新信息的演绎式分类器。

根据实施例的第二步骤,检索节点之间的引用的语义描述,以用于由目标本体的至少一个谓词和/或至少一个类来表达语义描述。

谓词是语义三元组的一部分,语义三元组是根据万维网联盟(w3c)的规范由资源描述框架(rdf)中的数据模型组织的本体的原子数据条目。三元组是三个实体的集合,该集合以主语-谓语-宾语表达式的形式来编纂(codify)关于语义数据的陈述。三元组通常被组织并且存储在名为三元组存储的数据库中。

虽然该实施例的第一步骤涉及节点标识的映射,但是第二步骤旨在将语义描述映射到本体的一个或多个谓词。映射具体地意味着应用规则来检索或解析在opcua的数据模型内分散的语义描述,利用共同概念对这些语义描述进行分类,以及将经分类的概念包摄(subsume)到语义本体语言中的形式数据表示。

在如rdf、rdfs或rdf模式的其他语义本体语言当中的优选语义本体语言是由被称为owl或web本体语言的语言族来提供的。根据资源描述框架或rdf、按照针对对象的w3c的xml标准来构造owl语言族。与rdf相结合的owl在实现用于创造本体的知识表示方面具有广泛的传播(dissemination)。

在下文中,具有一个或多个中间大写字母(medialcapital)的复合名称——例如复合名称»类型定义节点(typedefinitionnodes)«——用于指代opc基金会的规范»opc统一架构«或者owl规范中使用的权威性名称。这些权威性名称被假设是已知的,并且是本领域技术人员已知的。因此,在下文,在不进行解释的情况下引入这些权威性名称。

以下opcua引用包括要由目标本体的至少一个谓词表达或映射到该至少一个谓词的合适语义描述:

-类型定义节点(变量类型(variabletype)、对象类型(objecttype))

-实例声明

-浏览名称和其他属性

-引用类型

-地址空间的结构(例如,视图)

-数据类型(例如,结构-数据类型)

以下部分定义了如何将opcua语义变换成本体或owl类概念。owl的以下本体类概念在适用于映射的opcua的语义内具有适当的对应物(counterpart):

-类概念»基本(base)«是从opcua的基本节点类(basenodeclass)和每个具体实例节点类的超级类型中派生的。

-类概念»数据类型«与数据类型层级结构相同,其可以在根/类型/数据类型下找到。

-类概念»实例声明«是帮助者(helper)概念,用于将对应的验证规则添加到该概念。

-类概念»方法类型(methodtype)«是帮助者类,用于覆盖和标记所有方法语义。可以基于方法的浏览名称和对象类型来捕获语义。

-类概念»对象类型«与对象类型层级结构相同,其可以在根/类型/对象类型下找到。然而,在该层级结构中还可以找到对象相关的实例声明。

-类概念»类排名帮助者(valuerankhelper)«是帮助者概念,用于将对应的验证规则添加到该概念。

-类概念»变量类型«与变量类型层级结构相同,其可以在根/类型/变量类型下找到。然而,在该层级结构中还可以找到变量实例声明(variable-instancedeclaration)。

类概念»实例声明«包括子类方法实例声明(methodinstancedeclaration)、对象实例声明(objectinstancedeclaration)和变量实例声明。opcua规范的部分3、章节6.3.6中关于实例声明的实例的限制是结合owl数据性质限制、使用owl类和子类概念来建模的。

类概念»数据类型«是结合opcua变量和opcua变量类型或variabletype、使用对数据类型的限制来构建的。»数据类型«类概念是结合owl对象性质限制和owl联合概念、使用owl类和owl子类概念来构造的,以便构造数据类型字段语义,从而进一步包括对数据类型字段约束的结构的限制,如数据类型。示例性数据类型是32位长无符号整数或uint32。

类概念»方法类型«是针对所有实例声明方法的顶级概念。方法的语义定义与性质相当(comparable)。典型的方法是由«所属对象(owningobject)«和所指派的浏览名称来定义的。以下规则将被应用于构造方法类型概念:

-尝试将具有相同浏览名称的所有方法节点映射到一个概念,而不管所属对象。该规则类似于性质浏览名称,然而,如果该映射是不可能的,则必须引入析取概念(disjunctiveconcept)。

-出于验证目的,引入了类概念«方法类型«下的子类型,该子类型基于占位符建模规则。

类概念«对象类型«用于捕获opcua概念的语义,并且指派对应实例声明和建模规则的限制。对象类型由包括标签、注解等的注释性质(annotationproperty)组成。本体中的类概念是结合owl数据性质限制和owl注释性质、使用owl类和owl子类概念来建模的。owl数据性质限制是在opcua规范的部分3中、根据在opcua规范中被形式化的规则来建模的。

通过类概念«值排名帮助者«,关于opcua节点的属性“值排名”的限制是结合owl数据性质限制、使用owl类和owl子类概念根据opcua部分3、章节5.6.5和6.2.7来建模的。根据opcua部分3、章节6.2.7c)的一个示例性约束读出如下:

如果未提供数组维数(arraydimension)属性、或者在将数组中的条目的值从0修改为不同的值时,可以添加数组维数属性。数组中的所有其他值都应保持相同。

该约束被映射到正则表达式或regex模式,如例如:

arraydimensionssomexsd:string[pattern"\\[1,[0-9]{0,3},1\\]"]"

类概念«变量类型«用于捕获opcua概念的语义,并且指派对应实例声明和建模规则的限制。变量类型由包括标签、注解等的注释性质组成。本体中的类概念是结合owl数据性质限制、owl对象性质限制和owl注释性质、使用owl类和owl子类概念来建模的。owl数据性质限制是在opcua规范的部分3中、根据在opcua规范中被形式化的规则来建模的。

性质是在本体中通过以下映射规则来建模的。性质及其浏览名称的定义(即,性质浏览名称)被引入作为针对每个唯一性质-浏览名称的性质类型的子概念。该一般映射规则将确保具有相等的浏览名称的性质也将被映射到对应的性质-浏览名称概念。

顶级对象性质»objectproperties«可以用于实施(enforce)相同的个体推断。该概念不具有被指派给它的其他语义。

关于实例声明的浏览名称和结构字段名称概念,实例声明的每个浏览名称要被映射到对象性质。每个结构字段名称要被映射到对象性质,该对象性质具有结构-数据类型-名称空间的名称空间、以及带有字段名称的字符串部分。结构-数据类型-字段的描述可以被映射到rdfs:注解注释(rdfs:commentannotation)。

关于引用类型概念,opcua中的引用类型要被映射到本体中的对象性质。非对称的所有引用必须具有»逆(inverse)«对应物。基于»inverseof«公理,推理机可以自动推断双向引用,而不需要显式的建模。如果指定了逆名称(inversename)属性,则所述属性用于命名该概念。如果未指定逆名称属性,则将使用具有前缀»逆«的引用名称(referencename)(例如,逆层级式引用(inversehierarchicalreference))。为了确保逆引用的可靠推断,层级式引用树必须是完全镜像的。如果引用类型被定义为对称且层级式的,则该引用必须是正向和逆向树的子类型。对称引用(即,对称-属性被设置为真)也将通过把对称对象性质(symmetricobjectproperty)设置为真来反映。

本发明允许使用已经存在的语义web推理工具来验证opcua信息模型。另一个优点是如下事实:即,通过web本体语言(具体地是owl)的声明性性质,可以在不修改代码库的情况下处理新添加的规则。

本发明使得能够查询opcua数据模型。目前,还不存在用于查询opcua数据模型的可用的现成工具实现方式。通过使用根据本发明的映射来生成包括sparql引擎所需的rdf三元组的本体,对opcua数据模型的查询变得可行。然而,仅仅基于opcua节点来生成三元组是不够的。本发明提供了一种方法,其中以捕获opcua的语义的方式来生成三元组,从而提供了以极大量值减少用于制定(formulate)查询的努力的可能性。基于本发明的映射,语义web专家以及opcua专家能够制定查询。

本发明进一步使得能够分析opcua数据模型。基于opcua语义的形式表示,现在有可能进行如技能匹配、设备到机器中的载入、数据挖掘等任务。

要理解的是,所附权利要求中记载的元素和特征可以以不同的方式组合,以产生同样落入本发明范围内的新权利要求。因此,尽管下面所附的从属权利要求仅从属于单个独立或从属权利要求,但是要理解的是,可以替代地使这些从属权利要求从属于任何前面或后面的权利要求(无论是独立权利要求还是从属权利要求),并且这些新的组合应被理解为形成本说明书的一部分。

虽然上面已经参考各种实施例描述了本发明,但是应当理解的是,可以对所描述的实施例进行许多改变和修改。因此所意图的是,前述描述应被视为说明性的而不是限制性的,并且要理解的是,实施例的所有等同物和/或组合都意图被包括在本描述中。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1