内容分类 是任何一种这样的进程,即增强数据,以便采用让数据更容易搜索、归档、管理和集成到其他进程中的方式组织数据。产生这样的元数据,让您可以从现有内容获得更大的价值。
分类的重要问题之一是,人们根据自己的逻辑进行分类,会出现错误以及造成不同的分类。您定义分类系统时,考虑所有涉众的观点,试图找到一致的方法来组织数据,但是困难重重。例如,一个部门的人可能不明白什么样的元数据对另一个部门的人很重要。此外,培训人们去理解和一致地应用一种分类是很费时的。
随着海量数据(有些人称之为数字垃圾)的不断产生,手工对数据进行分类几乎已经是不可能的事了。您必须求助于分析各种格式和输入的自动化方法。
自动分类有很多优势:
本文中我编写的代码示例目的是跟 eXist XML Database 或 Zorba XQuery 处理器一起使用。要将它与 eXist XML Database 一起使用,您需要安装了该数据库;否则,使用 Zorba XQuery 处理器(可以通过在线沙箱得到)。
要安装 eXist XML Database,可执行以下步骤:
另外,通过执行以下步骤,您也可以使用 Zorba XQuery 处理器的在线版本来运行代码示例:
http://try.zorba-xquery.com/
处的 Zorba XQuery 处理器在线沙箱中。注意,eXist 和 Zorba 示例之间的差别很小。但是,眼尖的读者会注意到,它们使用 EXPath HTTP Client 库上有一点不同:Zorba 默认内置这个库,eXist 数据库则不这么做,因此,我提供一个单独的 http-client.xqm
XQuery 库,专门设计来与 eXist 一起使用。本文中的示例使用 EXPath HTTP Client 库访问远程数据和 web 服务。在本文的第二部分,您使用 Yahoo! Query Language (YQL) 和 AlchemyAPI 工具集成了更高级的处理。
注意:要明白,在使用这些服务之前,您可能需要同意接收一个 API 键。
本文的第一部分展示如何使用纯 XQuery 对内容进行分类。
术语 文本分析(text analytics)(或 文本挖掘(text mining))定义一组机器学习和语言技术,以从文本源抽取和建模信息元数据。文本分析在文本内容上应用自然语言处理(natural language processing,NLP)和分析方法,并抽取有用的元数据,比如:
文本挖掘的一个这样的例子是确定一个文档中包含的单词的频率,假设一个单词使用得越频繁,它就越与整个文档相关。
最常见的单词将被构造为文档关键词,但是要知道术语 关键词 通常应用于更复杂算法的输出,这些算法可比确定单词频率复杂多了。例如,关键词分析通常将常见单词与同义词查找表进行对照,也可以分析单词之间的距离,以帮助确定单词在整个文档上下文中的重要性。
任何文本分析中,第一步都是从文本内容生成一个语料库(corpus),后续的分析将应用于此语料库。生成语料库的原因之一是规范化文本并删除任何不相关的内容。
清单 1 展示了一个 XQuery 程序,它消费一个 HTML 页面(通过使用 EXPath HTTP Client 库)并从该 web 页面抽取出所有段落元素。由于不关心单词的大小写,所以您从内容创建的语料库全是小写的。
xquery version "1.0";import module namespace http = "http://expath.org/ns/http-client";let $content-url := 'http://en.wikipedia.org/wiki/Asteroid_impact_avoidance'let $content-request := <http:request href="{$content-url}" method="get" follow-redirect="true"/>let $content := fn:string-join(http:send-request($content-request)[2],' ')returnlet $corpus := for $w in tokenize($content, '\W+') return lower-case($w)let $wordList := distinct-values($corpus)return<words> {for $w in $wordListlet $freq := count($corpus[. eq $w])order by $freq descendingreturn <word word="{$w}" frequency="{$freq}"/>}</words>
下一步是从语料库中派生出所有惟一的单词,为此您使用一个 FLWOR 来处理每个单词,生成单词计数(通过向后引用语料库,其中包含所有的单词),然后输出一个 <word/>
元素。
注意:对于本文中的所有例子,我使用了相同的 web URL(http://en.wikipedia.org/wiki/Asteroid_impact_avoidance
)作为文本源,来演示每种方法的效果。
运行 清单 1 中程序的结果是一个 XML 文档,它具有一个 <word/>
元素,其中包含频率和单词,按照关于小行星防撞的 Wikipedia 页面中包含的最常见单词排序。清单 2展示了该列表。
<words><word word="the" frequency="377"/><word word="of" frequency="236"/><word word="a" frequency="193"/><word word="to" frequency="167"/><word word="and" frequency="141"/><word word="in" frequency="124"/><word word="earth" frequency="121"/><word word="a" frequency="109"/><word word="asteroid" frequency="102"/>....</words>
如您所见,分析返回了很多单词,根据在英语中的常见用途,很多使用频率高的单词是不相关的。可以通过定义一些简单的规则来解决这个问题,这些规则用于降低干扰,比如说去除所有三个字母以内的单词以及去除频率在 3 以内的单词。
清单 3 展示了相同的代码,但是添加了测试单词字符串长度和频率的逻辑。
xquery version "1.0";import module namespace http = "http://expath.org/ns/http-client";let $content-url := 'http://en.wikipedia.org/wiki/Asteroid_impact_avoidance'let $content-request := <http:request href="{$content-url}" method="get" follow-redirect="true"/>let $response := http:send-request($content-request)[2]let $content := fn:string-join($response,' ')returnlet $corpus := for $w in tokenize($content, '\W+') return lower-case($w)let $wordList := distinct-values($corpus)return<words> { for $w in $wordList let $freq := count($corpus[. eq $w]) order by $freq descending return if(string-length($w) gt 3 and $freq gt 3) then <word word="{$w}" frequency="{$freq}"/> else () }</words>
对于不同的数据集,您可能必须调整或增强这些设置,以便排除更大长度或更高频率的单词,但是如 清单 4 所示,最小设置忽略了很多干扰,得到一个更为相关的术语集合。
<words><word word="earth" frequency="121"/><word word="asteroid" frequency="102"/><word word="impact" frequency="58"/><word word="near" frequency="56"/><word word="with" frequency="55"/><word word="that" frequency="53"/><word word="space" frequency="49"/><word word="nasa" frequency="43"/><word word="object" frequency="36"/><word word="from" frequency="34"/><word word="this" frequency="32"/>...</words>
无疑,这种方法有其局限性。但是它是一个良好的开始,并且向您展示了,用不多的 XQuery 代码,就可以得到一组基本的描述文档文本内容特征的关键词。
生成元数据时通常需要作出的首要决策之一是,将元数据保存在内容 XML 中,还是存储在单独的元数据文档中。在确定了您想要将元数据存储到哪里之后,还需要决定以何种格式编码元数据。存在很多标记元数据的方式 — 例如:
rel-tag
直接在文档中注释关键词元素。semweb
标记格式可用,比如 Research Description Framework 和 Web Ontology Language。鼓励采用现有的特定标记语言,而不提倡设计自己的标记语言。但是要确保选择的格式既简单,又给元数据尽可能的灵活性。
如果完全忽略结构的话,应用于诸如 HTML 或 XML 之类半结构化文档的文本分析提供的见解很有限。但是如果您通过将内容与元素结构挂钩,给文本分析的重要性指定权值,从而得出更深层的推论,那又怎么样呢?
用 HTML 的术语来讲,如果您可以在某种程度上基于单词出现在嵌套结构中的何处而给单词打分,是不是很好?例如:
<title>
元素中的单词较重要。<noscript>
或 <script>
元素中的单词较不重要。<h1>
和 <h2>
元素中的单词较重要。要得到这种结构,向每个单词添加一个 fitness
属性。该属性执行一个检查,看单词是否特定出现在这些元素的哪一个中。清单 5展示了添加的逻辑,它进行检查以确定单词是否包含在任何被认为重要的元素中。
xquery version "1.0";import module namespace http = "http://expath.org/ns/http-client";let $content-url := 'http://en.wikipedia.org/wiki/Asteroid_impact_avoidance'let $content-request := <http:request href="{$content-url}" method="get" follow-redirect="true"/>let $response := http:send-request($content-request)[2]let $content := fn:string-join($response,' ')let $corpus := for $w in tokenize($content, '\W+') return lower-case($w)let $wordList := distinct-values($corpus)return<words> { for $w in $wordList let $fitness := if ( $response//*:title[contains(lower-case(.),$w)]) then 5 else if ($response//*:h1[contains(lower-case(.),$w)]) then 4 else if ($response//*:h2[contains(lower-case(.),$w)]) then 3 else if ($response//*:h3[contains(lower-case(.),$w)]) then 2 else if ($response//*:noscript[contains(lower-case(.),$w)]) then -2 else if ($response//*:script[contains(lower-case(.),$w)]) then -1 else 1 let $freq := count($corpus[. eq $w]) order by $freq descending return if ($freq gt 4 and string-length($w) gt 3) then <word word="{$w}" frequency="{$freq}" fitness="{$fitness}"/> else () }</words>
现在,您有了第二个度量,可以用来收集关于单词重要性的更多信息:
<title>
元素中的 <word word="asteroid" frequency="102" fitness="5"/>
。<h2>
元素中的 <word word="deflect" frequency="11" fitness="3"/>
。<script>
元素中的 <word word="false" frequency="7" fitness="-1"/>
,所以您给它一个负 fitness。这一 fitness 度量过于简单,因为可能出现这样的情况,即重要单词不知为何也出现在 <script>
部分,或者是,出现在 <title>
元素中的单词没有像您设想的那样对文档主体那么重要。对于给文档打分和生成更适当的关键词,您可以做出进一步的改进,但是我们这里将集成一些更重量级的工具,用于执行文本分析。
有很多商业和开源工具可用于执行自然语言处理 (NLP)。下面是一些最流行的开源软件包:
此外,有几个 web 服务提供有用的文本分析。本文的后半部分关注如何在 XQuery 文件中使用这些服务。您使用 EXPath HTTP Client 库来访问它们。
YQL 是一个类似于 SQL 的语言,使用它可以跨各种 Yahoo! web 服务查询数据。Yahoo! 用于使用一组 web 服务暴露大量数据和服务;现在,它使用不同的端点和方法通过单个接口 YQL 访问这些服务。
有了 YQL,您现在可以通过一种简单的语言跨 Internet 访问数据了,不再需要学习如何调用不同的 API。search.termextract
就是这样的一个服务,它从一组文本内容抽取公共术语。通过使用在线 YQL 控制台,您可以在浏览器上试用它:
http://developer.yahoo.com/yql/console/?q=select%20*%20from%20search.termextract%20where%20context%3D%22Italian%20sculptors%20and%20painters%20of%20the%20renaissance%20favored%20the%20Virgin%20Mary%20for%20inspiration%22
操作性 YQL 语句声明,从一个名叫 search.termextract
的表中选择 context 变量提供的文本。
select * from search.termextract where context=
单击 Test 生成包含一个 <query/>
元素的结果 XML,带有结果和一些诊断,如 清单 6 所示。
<query xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" yahoo:count="5" yahoo:created="2010-12-05T14:36:25Z" yahoo:lang="en-US"> <diagnostics> <publiclyCallable>true</publiclyCallable> <user-time>14</user-time> <service-time>11</service-time> <build-version>9962</build-version> </diagnostics> <results> <Result xmlns="urn:yahoo:cate">italian sculptors</Result> <Result xmlns="urn:yahoo:cate">virgin mary</Result> <Result xmlns="urn:yahoo:cate">painters</Result> <Result xmlns="urn:yahoo:cate">renaissance</Result> <Result xmlns="urn:yahoo:cate">inspiration</Result> </results></query>
由于从 XQuery 中使用 EXPath HTTP Client 库很容易,下面就在您自己的内容分类进程中使用它来访问 YQL web 服务。清单 7 展示了如何从 XQuery 中调用这个 web 服务。
xquery version "1.0";import module namespace http = "http://expath.org/ns/http-client";let $content-url := 'http://en.wikipedia.org/wiki/Asteroid_impact_avoidance'let $content-request := <http:request href="{$content-url}" method="get" follow-redirect="true"/>let $response := http:send-request($content-request)[2]let $content := fn:string-join(subsequence(($response//*:title,$response//*:p),1,10),' ')let $query := fn:concat("select * from search.termextract where context=",$content," ")let $query := fn:encode-for-uri( fn:concat("select * from search.termextract where context='",$content,"'") )let $yahoo-url :='http://query.yahooapis.com/v1/public/yql?diagnostics=true&q='let $term-extraction-url := fn:concat($yahoo-url,$query) let $term-extraction-request := <http:request href="{$term-extraction-url}" method="get"/>returnhttp:send-request($term-extraction-request)[2]
上面的 XQuery 代码使用 fn:encode-for-uri()
函数编码查询字符串。
YQL 分析生成一个更高质量的术语集合,如 清单 8 所示。
<query xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" yahoo:count="20"yahoo:created="2010-12-05T20:14:37Z" yahoo:lang="en-US"><diagnostics> <publiclyCallable>true</publiclyCallable> <url execution-time="433" >http://search.yahooapis.com/ContentAnalysisService/V1/termExtraction </url> <javascript execution-time="436" instructions-used="0" table-name="search.termextract"/> <user-time>437</user-time> <service-time>433</service-time> <build-version>9962</build-version></diagnostics><results> <Result xmlns="urn:yahoo:cate">tertiary extinction event</Result> <Result xmlns="urn:yahoo:cate">shoemaker levy 9</Result> <Result xmlns="urn:yahoo:cate">spaceguard survey</Result> <Result xmlns="urn:yahoo:cate">near earth objects</Result> <Result xmlns="urn:yahoo:cate">period comet</Result> <Result xmlns="urn:yahoo:cate">nasa report</Result> <Result xmlns="urn:yahoo:cate">extinction level event</Result> <Result xmlns="urn:yahoo:cate">deep impact probe</Result> <Result xmlns="urn:yahoo:cate">inner solar system</Result> <Result xmlns="urn:yahoo:cate">mitigation strategies</Result> <Result xmlns="urn:yahoo:cate">65 million years</Result> <Result xmlns="urn:yahoo:cate">material composition</Result> <Result xmlns="urn:yahoo:cate">impact winter</Result> <Result xmlns="urn:yahoo:cate">chicxulub crater</Result> <Result xmlns="urn:yahoo:cate">impact speed</Result> <Result xmlns="urn:yahoo:cate">catastrophic impact</Result> <Result xmlns="urn:yahoo:cate">catastrophic damage</Result> <Result xmlns="urn:yahoo:cate">planetary defense</Result> <Result xmlns="urn:yahoo:cate">impact events</Result> <Result xmlns="urn:yahoo:cate">astronomical events</Result></results></query>
YQL 也有局限性。例如,您必须确保传递给 YQL 的内容不超出请求限制。由于这些请求被作为 HTTP GET
请求发送,所以它们必须被正确编码。
AlchemyAPI 是一家公司,提供一组有趣的内容分析工具(参见 参考资料)。该公司的所有工具都作为一套 web 服务可用。在本文中,您使用他们的术语和指定实体抽取服务来执行文本分析。
AlchemyAPI 提供一个 web 服务,用于从任何可公共访问的 web 页面抽取主题关键词。使用一个直观的 HTTP GET
请求,您访问 AlchemyAPI web 服务,指示它检索某个特定的 URL,并抽取主题关键词。此外,AlchemyAPI URL处理调用自动获得想要的 web 页面,进行规范化和清洁(删除广告、导航链接和其他不重要的内容),并抽取主题关键词。清单 9 展示了这是如何实现的。
http://access.alchemyapi.com/calls/url/URLGetRankedKeywords?apikey=PLACE_YOUR_APIKEY_HERE& url=http://en.wikipedia.org/wiki/Asteroid_impact_avoidance
AlchemyAPI 需要两个 URL 参数:
您可以通过一个注册表单从 AlchemyAPI 站点获得 AlchemyAPI apikey。
由于 AlchemyAPI 为您获得 URL,所以从 XQuery 调用 web 服务比以前调用 YQL 的例子要稍微简单一些。清单 10展示了代码。
xquery version "1.0";import module namespace http = "http://expath.org/ns/http-client";let $url := 'http://en.wikipedia.org/wiki/Asteroid_impact_avoidance'let $apikey := 'PLACE_YOUR_APIKEY_HERE'let $alchemey_uri := 'http://access.alchemyapi.com/calls/url/URLGetRankedKeywords?'let $href := fn:concat($alchemey_uri,'&apikey=',$apikey,'&url=',$url)let $content-request := <http:request href="{$href}" method="get" follow-redirect="true"/>returnhttp:send-request($content-request)[2]
清单 11 展示了结果,其中包含所测试 web 页面的关键词。
<results> <status>OK</status> <usage>By accessing AlchemyAPI or using information generated by AlchemyAPI, you are agreeing to be bound by the AlchemyAPI Terms of Use: http://www.alchemyapi.com/company/terms.html</usage> <url>http://en.wikipedia.org/wiki/Asteroid_impact_avoidance</url> <language>english</language> <keywords> <keyword> <text>asteroid</text> <relevance>0.983321</relevance> </keyword> <keyword> <text>NASA</text> <relevance>0.376168</relevance> </keyword> <keyword> <text>comet</text> <relevance>0.370371</relevance> </keyword> <keyword> <text>near-earth object</text> <relevance>0.363529</relevance> </keyword> <keyword> <text>survey program</text> <relevance>0.3417</relevance> </keyword> .... more keywords .... </keywords></results>
由于关键词带有相关性分数(还有很多更相关的结果),所以从质量上来讲,来自 AlchemyAPI web 服务的输出比 YQL 更好一些。
通过使用 AlchemyAPI 指定实体抽取 web 服务,可以在复杂度上更进一步,AlchemyAPI 能够识别内容中的人、公司、组织、城市、地理特性和其他类型化实体。这里出现一些重型 NLP,以抽取有意义的实体。
跟主题关键词 web 服务一样,所有您必须做的事情就是提供一个 apikey 和 URL(包含您想要分析的内容),如 清单 12 所示。
http://access.alchemyapi.com/calls/url/URLGetRankedNamedEntities? apikey=PLACE_YOUR_APIKEY_HERE& url=http://en.wikipedia.org/wiki/Asteroid_impact_avoidance
就从 XQuery 调用 web 服务来说,您做的完全是相同的事情,如 清单 13 所示。
xquery version "1.0";import module namespace http = "http://expath.org/ns/http-client";let $url := 'http://en.wikipedia.org/wiki/Asteroid_impact_avoidance'let $apikey := 'PLACE_YOUR_APIKEY_HERE'let $alchemey_uri := 'http://access.alchemyapi.com/calls/url/URLGetRankedNamedEntities?'let $href := fn:concat($alchemey_uri,'&apikey=',$apikey,'&url=',$url)let $content-request := <http:request href="{$href}" method="get" follow-redirect="true"/>returnhttp:send-request($content-request)[2]
文本分析的结果相当冗长,并且如 清单 14所示,很清晰。
<results> <status>OK</status> <usage>By accessing AlchemyAPI or using information generated by AlchemyAPI, you are agreeing to be bound by the AlchemyAPI Terms of Use: http://www.alchemyapi.com/company/terms.html</usage> <url>http://en.wikipedia.org/wiki/Asteroid_impact_avoidance</url> <language>english</language> <entities> <entity> <type>GeographicFeature</type> <relevance>0.667231</relevance> <count>44</count> <text>Earth</text> </entity> <entity> <type>Organization</type> <relevance>0.472053</relevance> <count>25</count> <text>NASA</text> <disambiguated> <name>NASA</name> <subType>Company</subType> <subType>GovernmentAgency</subType> <subType>AirportOperator</subType> <subType>AwardPresentingOrganization</subType> <subType>SoftwareDeveloper</subType> <subType>SpaceAgency</subType> <subType>SpacecraftManufacturer</subType> <geo>38.88305555555556 -77.01638888888888</geo> <website>http://www.nasa.gov/home/index.html</website> <dbpedia>http://dbpedia.org/resource/NASA</dbpedia> <umbel>http://umbel.org/umbel/ne/wikipedia/NASA</umbel> <yago>http://mpii.de/yago/resource/NASA</yago> </disambiguated> </entity> .... entities .... </entities></results>
AlchemyAPI 指定实体抽取 web 服务识别了所有种类的实体。例如,它知道:
就这种意义上来说,文本挖掘从内容收集信息的能力几乎是不可思议的,但是最好关注一下相关性评分。没有哪个系统是百分之百准确的,您会发现某些内容对文本分析的响应要好于其他内容。
为开始分类您自己的文档,本文介绍了很多技术。第一种尝试的焦点是,如何基于确定单词频率,建立您自己的 XQuery 文本挖掘技术。我然后展示了如何集成 Yahoo! 和 AlchemyAPI 提供的强大的外部 web 服务,用于文本分析。
无疑,web 服务提供的文本分析质量较高,但是即使对于基本的单词频率 XQuery 例子,也可以使用纯 XQuery 从您的数据得到有用的推论。
给出的所有方法都有一些局限性。例如,只分析一个文档。跨一组相关文档执行文本分析可以导致更高质量的分类,因为您可以交叉引用更大的语料库,并分析出文档之间更深层的关系。总之,我希望本文向您展示了 XQuery 对于自动化内容分类有多么强大,并且愿意听到关于您自己尝试以相同方式应用 XQuery 的反馈。
描述 | 名字 | 大小 |
---|---|---|
本文的样例脚本 | content_catigorisation_src.zip | 20KB |
联系客服