AI 驱动的搜索:5 知识图谱学习
本章涵盖构建和使用知识图实现开放信息提取,从文本生成知识图谱使用语义知识图进行查询扩展和重写以及任意关系发现使用语义知识图解释文档以支持基于内容的文档推荐在上一章中,我们重点学习基于链接这些文档的众包交互的文档之间的关系。虽然这些交互主要是用户行为信号,但我们在本章结束时还讨论了文档本身中出现的文档之间的链接 - 例如,利用文档之间的超链接。在第二章中,我们还讨论了文档中的文本内容,而不是“非结构化数据”,实际上更像是一个巨大的“超结构化数据”图,其中包含连接许多字符序列、术语、以及我们文档集合中跨领域存在的短语。
在本章中,我们将演示如何利用内容中丰富关系的巨大图表,以便更好地解释您的特定领域术语。我们将通过使用传统知识图(支持对域内关系进行显式建模)和语义知识图(支持对域内细微语义关系进行实时推断)来实现这一目标。
我们还将在本章中使用几个有趣的数据集,以展示如何构建和应用知识图以改善跨不同领域的查询理解。
5.1 使用知识图在1.4节中,我们介绍了知识图的概念,并讨论了它们如何与其他类型的知识模型(例如本体、分类法、同义词和替代标签)相关。如果您还记得的话,知识图将其他类型的知识模型集成在一起,因此当我们在本章中构建和引用“知识图”时,我们将集中讨论它们。
知识图(或任何图)是通过节点和边的概念来表示的。节点通常也称为顶点,但我们将在本书中使用术语“节点”。节点是知识图中表示的实体(例如术语、人、地点、事物或概念),而边表示两个节点之间的关系。图 5.1 显示了显示节点和边的图形示例。
图 5.1。图结构。图由表示实体的“节点”(也称为“顶点”)和表示与另一个节点的关系的边组成
在该图中,您可以看到四个节点代表作者,一个节点代表他们共同撰写的一篇研究论文,一个节点代表论文发表和发表的学术会议,然后是代表城市、省、国家和日期的节点会议期间举行。例如,通过遍历(或“跟随”)节点之间的独立边,您可以推断其中一位作者于 2016 年 10 月在加拿大蒙特利尔。虽然任何具有像这样的节点和边的结构都被视为图,但这种特殊的图代表事实知识,因此也被视为知识图。
构建和表示知识图的方法有很多种,既可以通过将数据显式建模为包含节点和边的图,也可以通过所谓的语义知识图动态地从数据中具体化(发现)节点和边。在本章中,我们将介绍手动构建显式知识图、自动生成显式知识图以及利用搜索索引中已存在的语义知识图的示例。
要开始使用知识图,您基本上有三个选择:
使用图数据库(Neo4j、ArangoDB 等)从头开始构建您自己的知识图插入预先存在的知识图(ConceptNet、DBPedia 等)从您的数据自动生成知识图,直接利用您的内容来提取知识。每种方法都有其优点和缺点,并且它们不一定是相互排斥的。如果您正在构建通用知识搜索引擎(例如网络搜索引擎),那么利用第二个选项(利用预先存在的知识图)是一个很好的起点。然而,如果您的搜索引擎更加针对特定领域,那么您的特定领域实体和术语很可能不会出现,并且您确实需要创建自己的定制知识图。
在本章中,我们将主要关注第三个选项 - 从您的内容自动生成知识图。其他技术(手动生成知识图并利用预先存在的知识图)已经在外部材料中得到了很好的介绍 - 只需在网络上搜索 SPARQL、RDF Triples 和 Apache Jena 等技术或预先存在的知识图(例如DBPedia 和 Yago。话虽这么说,您最终需要能够覆盖您的知识图并添加您自己的内容,因此我们将提供如何集成显式定义(使用预定义关系的特定列表构建)和隐式定义的示例- 将定义的知识图(从数据中动态发现的自动生成的关系)添加到您的搜索平台中。
5.2 在搜索引擎中显式构建知识图许多组织花费大量资源为其组织构建知识图,但最终却无法找出将这些知识图集成到搜索引擎中的最佳方法。幸运的是,我们为我们的示例选择了一个搜索引擎(Apache Solr),它直接内置了显式图遍历功能,因此无需引入新的外部系统来实现或遍历本书中的知识图。
虽然使用 Neo4J 或 ArangoDB 等不同工具可能有一些优点,例如更复杂的图形遍历语义,但使用这样的外部图形数据库会使协调请求、保持数据同步和基础设施管理变得更加复杂。此外,由于某些图操作只能在搜索引擎中有效完成,例如我们很快就会遇到的语义知识图谱遍历,因此利用搜索引擎作为统一平台搜索和知识图谱功能使我们能够将最佳的两个世界。
我们将在第 7 章中广泛关注实现语义搜索搜索系统,包括语义查询解析、短语提取、拼写错误检测、同义词扩展和查询重写,所有这些都将被建模为显式构建的知识图谱。由于本章的目的是关注知识图谱学习,因此我们将把显式知识图谱构建和遍历的讨论保留到第 7 章,届时我们可以将本章和第 6 章(学习领域特定语言)中的所有内容联系在一起适当的知识图结构。
5.3 从内容中自动提取知识图谱正如我们在上一节中提到的,虽然有必要能够手动向知识图添加节点和边,但手动维护大规模知识图是非常具有挑战性的。它需要大量的主题专业知识,必须积极地跟上不断变化的信息,并且容易受到维护人员的偏见和错误的影响。
开放信息提取是自然语言处理 (NLP) 研究的一个不断发展的领域。开放信息提取旨在直接从文本内容中提取事实。这通常是使用 NLP 库和语言模型来解析句子并评估它们之间的依赖关系图来完成的。依存图是对句子中每个单词和短语的词性的细分,以及哪些单词引用哪些其他单词的指示。在本节中,我们将使用语言模型和依赖图来提取两种不同类型的关系:任意关系和下位关系。
5.3.1 从文本中提取任意关系考虑到文本的“超结构”性质以及典型句子和段落中表达的丰富关系,我们理所当然地应该能够识别句子的主语及其相互关联的方式。在本节中,我们将重点关注提取文本内容的句子中描述的实体之间的任意关系。
通过分析句子中的名词和动词,通常可以通过将句子的主语、动词和宾语映射到 RDF 三元组来推断句子中存在的事实。RDF 三元组是由三部分组成的数据点,表示主题(起始节点)、关系(边)和对象(结束节点)。例如,在句子“Colin就读Riverside High School”中,动词“attends”可以被提取为连接主语(“Colin”)和宾语(“Riverside High School”)的关系类型。因此,RDF 三元组是(“Colin”、“就读”、“Riverside High School”)。
清单 5.1演示了使用基于 Python 的 SpaCy 库从文本内容中提取事实的示例。Spacy 是领先的自然语言处理库,配备了最先进的统计神经网络模型,用于词性标记、依存分析、文本分类和命名实体识别。
清单 5.1。使用 SpaCy NLP 提取任意关系来关联名词和动词
text = """Data Scientists build machine learning models. They also write code.[CA]Companies employ Data Scientists.Software Engineers also write code. Companies employ Software Engineers."""def generate_graph(text): parsed_text = lang_model(text) parsed_text = resolve_coreferences(parsed_text) #1 sentences = get_sentences(parsed_text) #2 facts=list() for sentence in sentences: facts.extend(resolve_facts(sentence)) #3 return factsgraph = generate_graph(text)for i in graph: print(i)
结果:
sentence: Data Scientists build machine learning models.dependence_parse: ['nsubj', 'ROOT', 'dobj', 'punct']---------------------sentence: Data Scientists also write code.dependence_parse: ['nsubj', 'advmod', 'ROOT', 'dobj', 'punct']---------------------sentence: Companies employ Data Scientists.dependence_parse: ['nsubj', 'ROOT', 'dobj', 'punct']---------------------sentence: Software Engineers also write code.dependence_parse: ['nsubj', 'advmod', 'ROOT', 'dobj', 'punct']---------------------sentence: Companies employ Software Engineers.dependence_parse: ['nsubj', 'ROOT', 'dobj', 'punct']---------------------['Data Scientists', 'build', 'machine learning models']['Data Scientists', 'write', 'code']['Companies', 'employ', 'Data Scientists']['Software Engineers', 'write', 'code']['Companies', 'employ', 'Software Engineers']
正如您所看到的,示例代码已获取文本内容,将其解析为句子,然后确定这些句子中的主语、关系和宾语。然后可以将这些主题/关系/对象元组保存到显式构建的知识图中并进行遍历。
图 5.2 提供了该提取图的可视化。
图 5.2。提取的知识图
图 5.2 中的示例非常简单,并且存在更多复杂的算法来从更复杂的语言模式中提取事实。虽然我们在代码示例中使用 SpaCy 库,它利用基于深度学习的神经语言模型来检测词性、短语以及与输入文本的依赖关系和共同引用,然后我们利用该机制来解析这些内容语言输出更加基于规则,遵循英语中已知的语义模式。
不幸的是,当以这种方式将任意动词解析为关系时,提取的关系可能会变得非常嘈杂。由于动词的共轭方式不同,具有同义词,并且具有重叠的含义,因此通常需要修剪、合并或以其他方式清理任意提取的关系的任何列表。
相反,某些关系类型要简单得多,例如统计关系(“与……相关”)和下义关系(“是”)。我们将用本章的剩余部分来讨论这两种特殊类型,从下位词开始。
5.3.2 从文本中提取下位词虽然将任意动词映射到知识图中的清晰关系列表可能具有挑战性,但提取下位词和上位词可能要容易得多。下位词是与实体的更一般形式保持“是”或“是...的实例”关系的实体,更一般的形式称为上位词。例如,对于术语“十字头”、“螺丝刀”和“工具”之间的关系,我们会说“十字头”是“螺丝刀”的下位词,“工具”是“螺丝刀”的上位词,而“螺丝刀”又是“螺丝刀”的上位词。菲利普斯头和工具的下位词。
从文本中提取下位词/上位词关系的一种常见且相当准确的方法是使用赫斯特模式。[2] . 这些模式描述了常见的语言模板,可以可靠地指示句子中存在下义词。清单 5.2演示了此类模式的一些示例。
清单 5.2。识别下位词与其上位词关系的赫斯特模式示例
_hearst_patterns = [ ( '(NP_\\w+ (, )?such as (NP_\\w+ ?(, )?(and |or )?)+)', 'first' ), ( '(such NP_\\w+ (, )?as (NP_\\w+ ?(, )?(and |or )?)+)', 'first' ), ( '((NP_\\w+ ?(, )?)+(and |or )?other NP_\\w+)', 'last' ), ( '(NP_\\w+ (, )?include (NP_\\w+ ?(, )?(and |or )?)+)', 'first' ), ( '(NP_\\w+ (, )?especially (NP_\\w+ ?(, )?(and |or )?)+)', 'first' ),]
这五个简单模式中的每一个都表示为一个 Python 元组,第一个条目是正则表达式,第二个条目是模式匹配中的位置(即第一个或最后一个)。如果您不熟悉正则表达式,它们为字符串内的模式匹配提供了通用且强大的语法。在任何地方看到NP_字符,这代表句子中存在名词短语,并且元组的第二个元素中指定的位置(第一个或最后一个)指示句子中哪个名词短语代表上位词,所有其他名词短语都代表上位词。与该模式匹配的名词短语被视为下位词。
在清单 5.3的示例代码中,我们运行了近 50 个赫斯特模式来匹配内容中“is a”关系的许多组合。
清单 5.3。使用赫斯特模式提取下位关系
text_content = """Many data scientists have skills such as machine learning, python,[CA]deep learning, apache spark, or collaborative filtering, among othersJob candidates most prefer job benefits such as commute time, company[CA]culture, and compensation.Google, Microsoft, or other tech companies might sponsor the conference.Big cities, such as San Francisco, New York, and Miami appeal to new[CA]graduates.Many job roles, especially software engineering, registered nurse, and[CA]DevOps Engineer are in high demand.There are such job benefits as 401(k) matching, work from home, and[CA]flexible spending accounts.Programming languages, i.e. python, java, ruby and scala."""h = HearstPatterns()extracted_relationships = h.find_hyponyms(text_content)facts = list()for pair in extracted_relationships: factsend([pair[0], "is_a", pair[1]])print(*facts, sep="\n")
结果:
['machine learning', 'is_a', 'skill']['python', 'is_a', 'skill']['deep learning', 'is_a', 'skill']['apache spark', 'is_a', 'skill']['collaborative filtering', 'is_a', 'skill']['commute time', 'is_a', 'job benefit']['company culture', 'is_a', 'job benefit']['compensation', 'is_a', 'job benefit']['Google', 'is_a', 'tech company']['Microsoft', 'is_a', 'tech company']['San Francisco', 'is_a', 'big city']['New York', 'is_a', 'big city']['Miami', 'is_a', 'big city']['software engineering', 'is_a', 'job role']['registered nurse', 'is_a', 'job role']['DevOps Engineer', 'is_a', 'job role']['python', 'is_a', 'programming language']['java', 'is_a', 'programming language']['ruby', 'is_a', 'programming language']['scala', 'is_a', 'programming language']
正如您从清单 5.3中看到的,通过专注于提取固定类型(以及最流行的关系类型 - “is_a”关系),我们能够生成一个漂亮、干净的分类关系列表,其中包含更具体的术语(下位词)指向带有“is_a”边缘的更通用术语(上位词)。图 5.3 直观地展示了生成的图表。
图 5.3。源自赫斯特模式的知识图。我们可以看到所有节点都通过“is_a”边连接到其他节点。
上一节中任意关系提取所存在的不一致和噪音现在已经消失了。我们仍然可能对相似术语之间的关系存在歧义(例如,拼写错误、替代拼写、已知短语或同义词),但这些更容易解决。事实上,我们将在下一章中讨论如何从信号和内容中学习这种特定于领域的语言,以便在解释传入的用户查询时利用它。
虽然将文本中的信息提取到显式知识图中以供以后遍历可能很有用,但现实情况是,这种提取是一个有损过程,因为项目的表示与我们的项目中这些项目的原始上下文脱节。内容(周围的文本和包含该文本的文档)。在下一节中,我们将介绍一种完全不同类型的知识图谱——语义知识图谱——它经过优化,可以对内容中的术语和短语之间的关系进行实时遍历和排序,而无需显式构建和排序甚至不必将术语与其原始文本上下文分开。
[2]马蒂·赫斯特。“从大文本语料库中自动获取下位词”。1992. 第15届国际计算语言学会议
5.4 通过遍历语义知识图来学习意图在第 2 章 2.1-2.2 节中,我们讨论了文本内容是“非结构化数据”的神话,以及现实中文本文档如何表示超结构化数据。我们讨论了分布假设(“一个单词应该被它所保留的公司所知道”),并演练了如何将字符序列、术语和短语(或其他任意术语序列)视为与之间的相似概念相关的模糊外键。文件。我们还讨论了如何将文档之间的链接视为巨大关系图中的边,使我们能够了解文档语料库中存在的术语和实体的上下文含义。
在本节中,我们将介绍语义知识图,这是一种工具和技术,使我们能够遍历文档中存在的巨大语义关系图。
5.4.1 什么是语义知识图谱?语义知识图是一种“紧凑的自动生成模型,用于对域内的任何关系进行实时遍历和排名”。[3]虽然搜索引擎通常查找与查询相关的文档(查询与文档匹配)并对其进行排名,但我们可以将语义知识图视为搜索引擎,它查找并排名最匹配查询的术语。
例如,如果我们对有关健康主题的文档集合建立索引,并搜索“止痛药” advil,则advil语义知识图将自动(无需手动创建列表或数据建模)返回如下值,而不是返回包含该术语的文档。 :
advil 0.71motrin 0.60aleve 0.47ibuprofen 0.38alleve 0.37
像这样的结果可以被认为是“动态同义词”,但它们不是具有相同含义的术语,而是更像是概念上相关的术语。您可以扩展“advil”的传统搜索引擎查询以包含这些其他术语,例如,为了提高搜索结果的召回率或增强在概念上与 含义匹配的文档,而不仅仅是那些包含 5 个字母的advil文档一串a- d- v- i- l。
除了查找相关术语之外,语义知识图还能够在倒排索引中的字段之间进行遍历(“查找与该职位最相关的技能”),以深入遍历多个级别(“查找与该查询最相关的职位,然后找到与该查询和每个职位最相关的技能”),并使用您可以作为图形遍历中的节点发送到搜索引擎的任何任意查询来查找任何领域中语义相关的术语。
语义知识图的用例多种多样。它可用于查询扩展、生成基于内容的推荐、查询分类、查询消歧、异常检测、数据清理和预测分析。一旦我们获得用于测试语义知识图设置的数据集,我们将在本章的剩余部分中探索其中的几个。
5.4.2 数据集索引语义知识图在跨文档一起使用的术语有相当多重叠的数据集上效果最好。两个单词在文档中出现的频率越高,我们就越能确定这些术语在统计上是否比我们预期的出现的频率更高。
虽然维基百科对于许多用例来说通常是一个很好的起始数据集,但由于维基百科通常只有一个页面来介绍一个被认为具有权威性的主要主题,因此实际上各个文档之间并没有大量的重叠,这使得维基百科成为一个不太理想的数据集。这个用例。
话虽这么说,用户提交内容(问题、论坛帖子、职位发布、评论)的任何类型的网站都往往会为语义知识图用例提供出色的数据集。
在本章中,我们选择了两个主要数据集,一个工作数据集(工作委员会帖子)和一系列 StackExchange 数据转储,包括来自以下论坛的帖子:
healthscifidevopsoutdoorstravelcooking为了对数据集建立索引,请在运行任何语义知识图示例之前运行索引数据集 Jupyter 笔记本
5.4.3 语义知识图的结构为了充分利用语义知识图,根据其底层结构了解图的工作原理非常有用。
与必须显式建模为节点和边的传统知识图不同,语义知识图是从搜索引擎的底层倒排索引具体化的。这意味着要使用语义知识图,您所需要做的就是将文档索引到搜索引擎中。不需要额外的数据建模。
然后,倒排索引和相应的正向索引充当底层数据结构,支持对文档集合中存在的任何任意语义关系进行实时遍历和排序。图 5.4 演示了文档如何映射到正向索引和倒排索引。
图 5.4。倒排索引和远期索引
在图的左侧,可以看到三个文档,每个文档都有一个job_title字段、一个desc字段、一个skills字段。该图的右侧显示了这些文档如何映射到您的搜索引擎中。我们看到倒排索引将每个字段映射到一个术语列表,然后将每个术语映射到包含文档列表的倒排列表(以及文档中的位置,以及图中未包含的其他一些数据)。这使得查找任何领域中的任何术语并找到包含该术语的所有文档的集合变得快速高效。
然而,除了众所周知的倒排索引之外,您还会在图 5.4 的中间看到不太为人所知的正向索引。正向索引可以被认为是非倒排索引:对于每个字段,它将每个文档映射到该文档中包含的术语列表。搜索引擎使用正向索引在搜索结果上生成分面。在 Solr 和 Elasticsearch 等基于 Lucene 的搜索引擎中,通常通过启用在字段上调用的功能,在索引时为字段生成前向索引docValues。或者,Apache Solr 还允许您通过在查询时动态“反转”内存中的倒排索引来生成相同的正向索引,甚至可以在未添加到索引的字段上启用分面docValues。
如果您能够搜索任意查询并通过倒排索引查找文档集,然后您还能够获取任意文档集并在这些文档中查找术语,这意味着通过进行两次遍历(术语到文档到术语),您可以找到也一起出现在包含原始查询的文档中的所有相关术语。图 5.5 演示了这样的遍历是如何发生的,包括数据结构视图、集合论视图和图视图。
图 5.5。语义知识图的三种表示
在代表倒排索引和正向索引的数据结构视图中,我们根据术语是否出现在文档中来了解术语与文档的关系。这些“链接”最终仅在集合论视图中出现任意两个节点(术语)的文档之间存在交集时才出现。最后,图形视图演示了相同底层数据结构的第三种视图,但在这种情况下,我们看到节点(而不是文档集)和边(而不是相交的文档集)。本质上,我们的语义知识图作为倒排索引之上的抽象存在,该倒排索引已经在我们的搜索引擎索引内容时随时构建和更新。
我们通常认为搜索引擎的主要功能是接受查询、查找匹配文档并按相关性排名顺序返回这些文档。我们用第 3 章的全部内容来讨论这个过程,包括匹配(第 3.2.4 - 3.2.6 节)、TF*IDF 排名(第 3.1 节)和常用的 BM25 排名函数(第 3.2 节)。然而,通过语义知识图,我们专注于匹配和排名相关术语,而不是相关文档。
任何任意查询(任何可以用 Solr 语法表达的内容)都可以是图中的节点,并且您可以从该节点遍历到任何字段中的任何其他术语(或任意查询)。此外,由于两个节点之间的边的每次遍历都利用倒排索引(术语到文档)和正向索引(文档到术语),因此将这些遍历链接在一起形成多级图遍历是很简单的,如下所示图 5.6。
图 5.6。多级图遍历。在数据结构视图中,我们看到两次遍历,每次都是通过倒排索引,然后是正向索引
在图中,您可以看到从一项技能 ( java ) 到其他技能层 ( java、oncology、hibernate和scala ),再到职位头衔层 (软件工程师、数据科学家、java 开发人员) 的遍历。您会看到并非所有节点都已连接 - 例如,肿瘤学节点不会出现在图形遍历视图中,因为没有任何原始节点可以通过任何边连接到它,因为没有重叠文档。
鉴于并非所有可能的节点都与任何给定的遍历相关,语义知识图能够对节点之间的关系进行评分和分配权重也很重要,以便在任何图遍历期间可以对这些边进行优先级排序。我们将在下一节中介绍边缘的评分和权重分配。
5.4.4 计算边权重以对节点的相关性进行评分鉴于语义知识图的主要功能是发现节点之间语义关系的强度并对其进行评分(其中节点可以表示任何单词、短语或任意查询),因此生成语义相似度得分的能力至关重要。但“语义相似性”到底意味着什么?
如果你还记得第二章中介绍的分布假说,它说在相同上下文中一起出现且具有相似分布的单词往往具有相似的含义。直观上这是有道理的——术语“疼痛”或“肿胀”更有可能出现在还提到“advil”、“布洛芬”或“冰袋”的文档中,而不是一些随机文档中。但有趣的是,“冰袋”也可能出现在包含“冷却器”、“公路旅行”或“冷”等术语的文档中,而“advil”和“布洛芬”可能不会出现。
这些示例显示了具有相似含义的单词及其上下文,但我们也考虑诸如“a”、“the”、“of”、“and”、“if”、“they”以及无数其他非常常见/停用词的单词。事实上,这些词也会大量出现在“疼痛”、“肿胀”、“advil”、“布洛芬”或我们检查的任何其他词的相同上下文中。这指向分布假设的第二部分——这些词也必须以相似的分布出现。本质上,这意味着给定一定数量的包含第一个术语的文档,任何第二个术语如果与第一个术语同时出现在同一文档中的频率高于它在文档中同时出现的频率,那么它在语义上往往与第一个术语相似。与其他随机术语。
实际上,由于“the”或“a”往往与几乎所有其他术语共同出现,因此即使它们的共现水平很高,也不认为它们在语义上与这些术语相似。然而,对于像“疼痛”和“布洛芬”这样的术语,它们一起出现的频率在统计上比任一术语与随机其他术语一起出现的频率更高,因此它们被认为在语义上相似。
衡量这种语义相关性的一种简单方法是通过z以下相关性计算 (z ):
z = (countFg(x) - t\otalDocsFG * probBG(x)) / sqrt(t\otalDocsFG * probBG(x)[CA]* (1 - probBG(x))
这种相关性计算(概念上类似于正态分布中的“z 分数”)依赖于“前景”文档集和“背景”文档集的概念,并且使得术语“x”的分布能够两组之间进行统计比较。例如,如果前景集是与查询“pain”匹配的所有文档,并且背景集是所有文档,则单词“advil”的相关性将是“advil”在文档中出现的频率的度量包含单词“pain”(前景集)与任何随机文档(背景集)。
如果两个术语高度相关,则它们的相关性将是接近 的正数1.0。如果这些术语高度不相关(它们往往仅出现在不同的领域中),那么分数将更接近-1.0。最后,语义上根本不相关的术语(例如停用词)的相关性得分往往接近于零。
Apache Solr 将语义知识图功能直接内置到其分面 API 中。Faceting 提供了从术语到文档集再到术语的遍历能力,并且相关性聚合函数实现了我们刚刚描述的语义相似度计算。清单 5.4演示了在 Stack Exchange Health 论坛讨论的数据集中搜索“advil”,并使我们能够找到语义最相关的术语。
清单 5.4。发现相关节点。我们从原始查询“advil”遍历到文档“body”字段中语义最相关的术语(节点)。
collection="health"request = { "params": { "qf": "title body", "fore": "{!type=$defType qf=$qf v=$q}", "back": "*:*", "defType": "edismax", "rows": 0, "echoParams": "none", "omitHeader": "true" }, "query": "advil", "facet": { "body": { "type": "terms", "field": "body", "sort": { "relatedness": "desc"}, "mincount": 2, "limit": 8, "facet": { "relatedness": { "type": "func", "func": "relatedness($fore,$back)" } } } }}search_results = requests.post(solr_url + collection + "/select",[CA]json=request).json()for bucket in search_results["facets"]["body"]["buckets"]: print(str(bucket["val"]) + " " + str(bucket["relatedness"][ [CA]"relatedness"]))
结果:
advil 0.70986motrin 0.59897aleve 0.4662ibuprofen 0.38264alleve 0.36649tylenol 0.33048naproxen 0.31226acetaminophen 0.17706
正如您所看到的,在 Stackexchange Health 数据集中论坛帖子的任何文本中的所有术语中,与“advil”语义最相关的术语的排名顺序是一个很好、干净的其他止痛药列表,这些止痛药是最常用的止痛药。类似于“advil”。这就是利用分布假设通过语义相似性发现术语并对其进行排名的神奇之处 - 它为我们提供了动态自动发现关系的能力,可用于进一步提高我们对传入查询的理解。在下一节中,我们将讨论如何应用这种理解来提高查询相关性。
5.4.5 使用语义知识图进行查询扩展仅对搜索期间输入的关键字进行匹配和排名并不总是提供足够的上下文来查找最佳结果并对其进行排名。在这些情况下,您可以通过扩展或以其他方式增加查询以包含概念相关的术语,从而显着提高搜索结果的质量。在本节中,我们将介绍如何生成这些相关术语,并将演示应用这些术语来提高搜索结果质量的几种策略。
鉴于能够从任何关键字或查询开始,并找到任何领域中高度相关的其他术语,语义知识图的一个明显用例是动态扩展查询以包括相关术语。这使得文档能够匹配,这些文档不一定包含用户输入的确切关键字,但确实包含具有非常相似含义的其他术语。
例如,我们可以使用语义知识图来自动发现相关术语,然后匹配其他文档并提高搜索结果,而不是用户对“advil”的查询(来自我们上一个示例)仅匹配其中包含字符串“advil”的文档。相关性得分基于每个扩展术语的相关性得分。提交给搜索引擎的最终查询advil可能不是 ,而是类似advil OR motrin^0.59897 OR aleve^0.4662 OR ibuprofen^.3824 OR …。
让我们逐步了解实现这种查询扩展所需的步骤,这次利用来自不同域的数据集(我们的科幻数据集)。清单 5.5提供了此过程的第一步,在我们的科幻数据集上运行搜索晦涩的搜索词“vibranium”。
清单 5.5。发现未知术语的上下文。在这种情况下,对“vibranium”的模糊查询为任何不熟悉这个虚构术语的人带来了有用的上下文。
query = "vibranium"collection = "stackexchange"request = { "query": query, "params": { "qf": "title body", "fore": "{!type=$defType qf=$qf v=$q}", "back": "*:*", "defType": "edismax", "rows": 0, "echoParams": "none", "omitHeader": "true" }, "facet": { "body": { "type": "terms", "field": "body", "sort": { "relatedness": "desc"}, "mincount": 2, "limit": 8, "facet": { "relatedness": { "type": "func", "func": "relatedness($fore,$back)" } } } }}search_results = requests.post(solr_url + collection + "/select",[CA]json=request).json()for bucket in search_results["facets"]["body"]["buckets"]: print(str(bucket["val"]) + " " + str(bucket["relatedness"][ [CA]"relatedness"]))
结果:
vibranium 0.92227wakandan 0.75429wakanda 0.75295adamantium 0.7447panther's 0.69835klaue 0.68083klaw 0.65195panther 0.65169
对于任何不熟悉“振金”一词的人来说,它是一种存在于漫威漫画书和电影中的坚固的虚构金属(通过 2018 年好莱坞热门电影《黑豹》而最为流行)。返回的最相关的术语与“瓦坎达”(振金的起源地)、“金刚合金”(漫威漫画中的另一种强(虚构)金属)以及“黑豹”(来自黑豹这个名字)有关。 Klaue 这个名字和另一种拼写 Klaw 是《黑豹》漫画书和电影中的一个角色,与金属振金密切相关。
您可能熟悉也可能不熟悉振金或任何这些相关信息 - 而您不需要的事实正是自动生成的知识图如此有用的原因。通过利能够提高排名靠前的搜索结果的精确度。
清单 5.6演示了将原始查询与语义知识图输出一起转换为扩展查询的示例。
清单 5.6。从语义知识图返回的相关节点生成扩展查询。
query_expansion = ""terms = search_results["facets"]["body"]["buckets"]for bucket in search_results["facets"]["body"]["buckets"]: term = bucket["val"] boost = bucket["relatedness"]["relatedness"] if len(query_expansion) > 0: query_expansion += " " query_expansion += " " + term + "^" + str(boost)expanded_query = query + "^5" + query_expansionprint("Expanded Query:\n" + expanded_query)
结果:
Expanded Query:vibranium^5 vibranium^0.92228 wakandan^0.75429 wakanda^0.75295[CA]adamantium^0.7447 panther's^0.69835 klaue^0.68083 klaw^0.65195[CA]panther^0.65169
在本例中,我们对与原始查询 ( ) 相关的任何关键字进行简单的布尔 OR 搜索vibranium,将原始查询术语的权重提高 5 倍,并根据其语义对每个后续术语对相关性得分的影响进行加权相似度得分。将原始术语提升 5 倍的选择是任意的 - 您可以在此处选择任何值来指定相对于其他(扩展的)术语的相对相关性提升。
您可能还注意到术语振金出现了两次 - 第一次作为原始术语,然后再次作为扩展术语(因为该术语在语义上也与其自身最相似)。如果您搜索单个关键字,情况几乎总是如此,但由于您的查询可能包含短语或其他结构,使原始查询与实际返回的术语(如果有)不同,因此通常最好仍然包含原始查询作为扩展/重写查询的一部分,这样用户就不会因为它被忽略而感到沮丧。
虽然之前的扩展查询应该很好地对结果进行排名(优先考虑匹配多个相关术语的文档),但它也非常注重召回率(扩展以包括任何相关的内容)而不是精度(确保包含的所有内容都是相关的)。有许多不同的方法来构建增强查询,具体取决于您的主要目标。
重写的查询可以执行简单的扩展,需要匹配的术语的最小百分比或数量,需要匹配原始查询等特定术语,甚至只是更改相同初始结果集的排名。清单 5.7演示了几个示例,利用最小匹配阈值和百分比,可以根据需要在精确度和召回率之间倾斜。
清单 5.7。不同的查询增强策略。
_expansion = 'q={!edismax qf="title body" mm="0%"}' + query + " " +[CA]query_expansionincrease_conceptual_precision = 'q={!edismax qf="title body" mm="30%"}' +[CA]query + " " + query_expansionincrease_precision_reduce_recall = 'q={!edismax qf="title body" mm="2"}' +[CA]query + " AND " + ( query_expansion + )same_results_better_ranking = 'q={!edismax qf="title body" mm="2"}' + query[CA]\ + "&boost=" + "query($expanded_query)&expanded_query=" +[CA]query_expansionprint("Simple Query Expansion:\n" + _expansion)print("\nIncreased Precision, Reduced Recall Query:\n" +[CA]increase_conceptual_precision)print("\nIncreased Precision, No Reduction in Recall:\n" +[CA]increase_precision_reduce_recall)print("\nSlightly Increased Recall Query:\n" + slightly_increased_precision)print("\nSame Results, Better Conceptual Ranking:\n" +[CA]same_results_better_ranking)
每种不同查询扩展技术的最终查询如下:
简单查询扩展:
q={!edismax qf="title body" mm="0%"}vibranium vibranium^0.92227[CA]wakandan^0.75429 wakanda^0.75295 adamantium^0.7447 panther's^0.69835[CA]klaue^0.68083 klaw^0.65195 panther^0.65169
这个简单的查询扩展与前面描述的相同,匹配包含原始查询或任何语义相关术语的任何文档。
提高精确度,减少召回查询:
q={!edismax qf="title body" mm="30%"}vibranium vibranium^0.92227[CA]wakandan^0.75429 wakanda^0.75295 adamantium^0.7447 panther's^0.69835[CA]klaue^0.68083 klaw^0.65195 panther^0.65169
此示例指定“最小匹配”阈值 30% ( mm=30%),这意味着为了使文档匹配,它必须至少包含查询中 30%(向下舍入)的术语。
提高精确度,不降低召回率:
q={!edismax qf="title body" mm="2"}vibranium AND (vibranium^0.92227[CA]wakandan^0.75429 wakanda^0.75295 adamantium^0.7447 panther's^0.69835[CA]klaue^0.68083 klaw^0.65195 panther^0.65169)
该查询要求原始查询术语(vibranium)匹配,并且还要求至少两个术语匹配(vibranium再加上一个术语)。这意味着文档必须包含原始查询之外的附加术语,但还必须仍然与原始查询匹配。
略微增加召回查询:
q={!edismax qf="title body" mm="2"}vibranium vibranium^0.92227[CA]wakandan^0.75429 wakanda^0.75295 adamantium^0.7447 panther's^0.69835[CA]klaue^0.68083 klaw^0.65195 panther^0.65169
此查询需要两个术语进行匹配,但并不明确需要原始查询,因此它可以扩展到概念上相似但不一定必须包含原始查询术语的其他文档。由于该术语vibranium重复两次,因此任何仅包含该单词的文档vibranium也将匹配。
相同的结果,更好的概念排名:
q={!edismax qf="title body" mm="2"}vibranium&boost=query($expanded_query)&expanded_query=vibranium^5 vibranium^0.92227 wakandan^0.75429[CA]wakanda^0.75295 adamantium^0.7447 panther's^0.69835 klaue^0.68083[CA]klaw^0.65195 panther^0.65169
最终查询返回与 的原始查询完全相同的文档vibranium,但根据它们与知识图中语义相似术语的匹配程度对它们进行不同的排名。这确保了关键字存在于所有匹配的文档中,并且返回包含用户查询的所有文档,然后可以大大提高排名,以更好地理解该术语的特定领域上下文,从而提升更多相关文档。
当然,在重写查询以包含增强的语义上下文时,您可以探索无限数量的可能的查询排列,但上面的示例应该可以很好地了解可用选项的类型以及您需要考虑的权衡。
5.4.6 使用语义知识图进行基于内容的推荐在上一节中,我们探讨了如何通过发现和利用语义知识图中的相关节点来增强查询,包括构建重写查询以优化精度、召回率甚至改进相同结果的概念排名的多种方法。除了使用语义相关术语扩展查询之外,还可以使用语义知识图谱,根据文档中术语的语义相似性将文档翻译为查询,从而生成基于内容的推荐。
由于语义知识图中的节点可以表示任何任意查询,因此我们可以从文档(单个术语、短语或其他值)中获取内容,并将它们建模为要相对于文档的某些已知上下文进行评分的任意节点。这意味着我们可以从文档中获取数十或数百个术语,对它们与文档主题相关的所有术语进行评分,然后获取语义上最相似的术语并使用它们生成最能代表细微差别的上下文含义的查询该文件。
清单 5.8演示了一个翻译被分类为“星球大战”文档并对文档中与该主题相关的所有术语进行排名的示例。
清单 5.8。基于内容的推荐。我们可以将文档的术语和短语传递到语义知识图谱,对它们与文档主题的语义相似度进行评分,并生成表示文档中语义上最重要的元素的查询。
import collectionsfrom mergedeep import mergeprint(solr_url)collection="stackexchange"classification="star wars"document="""this doc contains the words luke, magneto, cyclops, darth vader, princess leia, wolverine, apple, banana, galaxy, force, blaster, and chloe."""#run an entity extractor to parse out keywords to scoreparsed_document = ["this", "doc", "contains", "the", "words", "luke", \ "magneto", "cyclops", "darth vader", "princess leia", \ "wolverine", "apple", "banana", "galaxy", "force", \ "blaster", "and", "chloe"]request = {"query": classification, "params": {}, "facet": {}}i=0for term in parsed_document: i+=1 key = "t" + str(i) key2 = "${" + key + "}" request["params"][key] = term request["facet"][key2] = { "type": "query", "q": "{!edismax qf=${qf} v=" + key2 + "}", "facet": {"stats": "${relatedness_func}"} }print(json.dumps(request,indent=" "))full_request = merge(request_template, request)search_results = requests.post(solr_url + collection + "/select",[CA]json=full_request).json()def parse_scores(search_results): results = collections.OrderedDict() for key in search_results["facets"]: if key != "count" and key != "" and "stats" in search_results[ [CA]"facets"][key]: relatedness = search_results["facets"][key]["stats"][ [CA]"relatedness"] results[key] = relatedness return list(reversed(sorted(results.items(), key=lambda kv: kv[1])))scored_terms = parse_scores(search_results)for scored_term in scored_terms: print (scored_term)
生成的知识图谱查找:
{ "query": "star wars", "params": { "t1": "this", "t2": "doc", "t3": "contains", "t4": "the", "t5": "words", "t6": "luke", "t7": "magneto", "t8": "cyclops", "t9": "darth vader", "t10": "princess leia", "t11": "wolverine", "t12": "apple", "t13": "banana", "t14": "galaxy", "t15": "force", "t16": "blaster", "t17": "and", "t18": "chloe" }, "facet": { "${t1}": { "type": "query", "q": "{!edismax qf=${qf} v=${t1}}", "facet": { "stats": "${relatedness_func}" } }, ... "${t18}": { "type": "query", "q": "{!edismax qf=${qf} v=${t18}}", "facet": { "stats": "${relatedness_func}" } } }}
评分节点:
('luke', 0.66366)('darth vader', 0.6311)('force', 0.59269)('galaxy', 0.45858)('blaster', 0.39121)('princess leia', 0.25119)('this', 0.13569)('the', 0.12405)('words', 0.08457)('and', 0.07755)('contains', 0.04734)('banana', -0.00128)('doc', -0.00185)('cyclops', -0.00418)('wolverine', -0.0103)('magneto', -0.01112)('apple', -0.01861)
从这些结果中,您可以看到文档中的术语列表,该列表根据与“星球大战”主题的语义相似性进行了很好的排序。得分较低的术语与指定主题没有相关性或负相关性。如果我们过滤出正相关性以上的术语,如0.25清单 5.9所示,我们会从文档中获得一个非常干净的相关术语列表。
清单 5.9。将评分短语从文档映射到查询,过滤掉低相关性分数。
rec_query = ""for scored_term in scored_terms: term = scored_term[0] boost = scored_term[1] if len(rec_query) > 0: rec_query += " " if boost > 0.25: rec_query += term + "^" + str(boost)print("Expanded Query:\n" + rec_query)
扩展查询:
luke^0.66366 "darth vader"^0.6311 force^0.59269 galaxy^0.45858[CA]blaster^0.39121 "princess leia"^0.25119
清单 5.10演示了此过程的最后一步,实际运行搜索以返回在语义上与原始文档最相似的排名靠前的文档。
清单 5.10。基于内容的推荐请求将评分术语作为查询传递。
import collectionscollection="stackexchange"request = { "params": { "qf": "title body", "defType": "edismax", "rows": 5, "echoParams": "none", "omitHeader": "true", "mm": "0", "fl": "title", "fq": "title:[* TO *]" #only show docs with titles to make the example readable }, "query": rec_query}search_results = requests.post(solr_url + collection + "/select",[CA]json=request).json()print(json.dumps(search_results, indent=" "))
结果:
{ "response": { "numFound": 2511, "start": 0, "docs": [ { "title": "Did Luke know the "Chosen One" prophecy?" }, { "title": "Why couldn't Snoke or Kylo Ren trace Luke using the Force?" }, { "title": "Was Darth Vader at his strongest during Episode III?" }, { "title": "Was/is Darth Vader the most powerful force user?" }, { "title": "Who/what exactly does Darth Vader believe taught Luke [CA]between the events of “The Empire Strikes Back” and “Return of [CA]the Jedi?”" } ] }}
正如您所看到的,我们刚刚创建了一个基于内容的推荐算法。我们在第 4 章中讨论了利用用户行为信号(搜索、点击等)生成推荐(协作过滤)的想法,但我们并不总是有足够的信号来仅仅依赖基于信号的推荐方法。因此,能够根据起始文档的内容获取文档并查找其他类似文档,为我们提供了一个出色的附加工具,我们可以使用该工具提供上下文和领域感知的推荐,而无需依赖用户信号。
虽然本节中的示例根据起始文档中实际的术语生成了基于内容的推荐查询,但值得注意的是,语义知识图并不限于使用传入的术语。您可以添加额外的级别遍历以查找与原始文档中的术语语义相关但实际上不包含在其中的其他术语。这对于没有足够文档与推荐查询匹配的利基主题特别有用,因为进一步遍历将为探索开辟新的可能性。
在下一节中,我们将快速超越“is_related_to”关系,看看是否可以利用语义知识图来生成和遍历一些更有趣的边。
5.4.7 使用语义知识图来建模任意关系到目前为止,我们所有的语义知识图遍历都利用了“is_related_to”关系。也就是说,我们一直在使用相关性函数来查找两个单词或短语之间的语义关系的强度,但我们只测量了节点是否“相关”,而不是它们如何相关。如果我们可以在节点之间找到其他类型的边而不仅仅是“is_lated_to”类型的边怎么办?在本节中,我们将探讨如何做到这一点。
如果您还记得的话,语义知识图中的节点是通过执行与一组文档匹配的查询来动态实现的。如果您从 开始的节点是engineer,则该节点在内部表示为包含该单词的所有文档的集合engineer。如果节点标记为software engineer,则该节点在内部表示为包含该术语的所有文档software与包含该术语的所有文档相交的集合engineer。如果搜索是 for "software engineer" OR java,那么它在内部表示为包含该术语(短语)software之前一个位置的术语的所有文档的集合,与包含该术语的所有文档的集合并集。所有查询,无论其复杂程度如何,都在内部表示为一组文档。engineerjava
您可能还记得,边是通过查找两个节点共同共享的文档集来形成的。这意味着节点和边都使用相同的机制(一组文档)在内部表示。实际上,这意味着如果我们可以使用近似有趣关系(而不是实体)的查询来构造一个节点,那么我们可以通过“关系节点”将两个节点关联在一起,就像边的方式一样用于将传统图结构中的节点关联在一起。
让我们来看一个例子。重新审视我们的科幻数据集,假设我们想问一个有关“Jean Grey”的问题,“Jean Grey”是 Marvel Comics X-Men 漫画书、电视节目和电影中的热门角色之一。具体来说,假设我们想弄清楚谁爱上了琴·葛蕾。
我们可以通过使用起始节点“Jean Grey”,遍历到节点“in love with”,然后请求在“Jean Grey”的上下文中与“in love with”相关联的最相关术语来完成此操作。清单 5.11演示了这个查询。通过遍历旨在捕获显式语言关系(在本例中为“爱上”)的节点,我们可以使用中间节点来对起始节点和终止节点之间的边进行建模。
清单 5.11。通过“关系节点”实现边缘。collection = "scifi"starting_node = '"jean grey"'relationship = '"in love with"'request = { "query": starting_node, "params": { "qf": "body", "fore": "{!type=$defType qf=$qf v=$q}", "back": "*:*", "defType": "edismax", "rows": 0, "echoParams": "none", "omitHeader": "true" }, "facet": { "in_love_with":{ "type": "query", "query": "{!edismax qf=body v=$relationship}", "facet": { "terminating_nodes": { "type": "terms", "field": "body", "mincount": 25, "limit": 9, "sort": { "body_relatedness": "desc"}, "facet": { "body_relatedness": { "type": "func", "func": "relatedness($fore,$back)" } } } } } }}search_results = requests.post(solr_url + collection + "/select",[CA]json=request).json()for bucket in search_results["facets"]["in_love_with"][[CA]"terminating_nodes"]["buckets"]: print(str(bucket["val"]) + " " + str(bucket["body_relatedness"][ [CA]"relatedness"]))
结果:
jean 0.85044grey 0.74965cyclops 0.61313summers 0.60624xavier 0.54697wolverine 0.49361x 0.46596mutant 0.46248magneto 0.43692
如果 X 战警漫画或回复中出现的名字对你来说不熟悉,这里有一个快速速成课程:琴·格雷与两个变种人有反复的关系,一个名叫独眼巨人(真名:斯科特·萨默斯),另一个名叫金刚狼。此外,大多数粉丝不知道的是,琴·格雷的两位导师查尔斯·泽维尔教授和万磁王在漫画中多次对琴·格雷产生了爱情兴趣。
如果我们检查清单 5.7的结果,我们会看到列出了所有这些预期的名称。前两个术语jean和grey显然是最相关的,因为我们正在搜索in love相对于jean grey,所以她的名字显然在语义上与其本身高度相关。接下来的两个术语cyclops都summers指同一个人,即吉恩最突出的恋人。然后我们看到xavier和wolverine,列表中的最终结果是magneto。图 5.7 直观地演示了此遍历的底层图形关系。
图 5.7。遍历任意定义的边类型
通过使用中间节点(即in love with)来建模其他节点之间的关系,我们可以在节点之间形成任意类型的边,只要我们可以将该边表示为搜索查询即可。
虽然清单 5.11中的图形遍历结果总体上相当不错,但我们确实看到术语x(大概来自“x-men”) 和mutant也出现了。琴·格雷和所有其他列出的人都是 X 战警漫画中的变种人,这就是为什么这些术语在语义上如此相关。然而,它们显然不是“谁爱上了琴·葛蕾?”这个问题的好答案。
这就引出了一个重要的观点:语义知识图谱是统计知识图谱。“爱上”关系的存在纯粹基于我们集合中术语的统计相关性,因此就像任何本体学习方法一样,都会有噪音。话虽这么说,对于没有显式实体建模的自动生成图(我们只是索引了单个关键字,没有感觉它们代表人),这些结果实际上相当不错。
如果我们想提高这些结果的质量,最简单的事情之一就是对内容进行预处理以提取实体(人物、地点和事物)并对它们进行索引,而不仅仅是单个术语关键字。这将导致返回实际的人名(即“Scott Summers”、“Charles Xavier”、“Jean Grey”),而不仅仅是单个关键字( 、summers、xavier、jean)grey。
还值得指出的是,关系的遍历完全取决于这些关系是否在底层文档语料库中进行了讨论。在这种情况下,存在大量论坛帖子讨论这些人与琴·格雷的关系。如果存在的文档不足,返回的结果可能很差或不存在。为了避免结果中出现噪音,我们将mincount阈值设置为25,这表明必须存在至少 25 个文档讨论“jean grey”、“in love with”以及找到并评分的其他术语。我们建议将mincount设置为大于1的数字,以避免误报。
虽然从探索的in love with角度探索任意语言关系可能很有用,但从查询理解的角度来看,坚持默认的“与……相关”关系并仅利用大多数语义搜索用例的术语之间的相关性分数通常就足够了。然而,遍历多个级别的关系以生成更好的上下文仍然很有用。具体来说,从术语遍历到分类字段以提供一些附加上下文,然后遍历该类别中术语的相关含义可能很有用。我们将在第 6 章中更详细地介绍这一策略,其中我们将重点关注消除具有多种含义的术语的歧义。
[3]特雷·格兰杰等人。“语义知识图:一个紧凑的自动生成模型,用于对域内的任何关系进行实时遍历和排名。” 2016 年 IEEE 国际数据科学和高级分析会议 (DSAA) (2016):420-429。
5.5 使用知识图谱进行语义搜索通过提供接受任意查询并以上下文敏感的方式动态发现相关术语的能力,语义知识图成为查询解释和相关性排名的关键工具。我们已经看到,语义知识图不仅可以帮助解释和扩展查询,而且还提供动态分类查询和关键字的能力,以及消除每个查询中术语的多种含义的歧义。
我们还在本章的早期探讨了如何手动和通过开放信息提取技术构建显式知识图,以及如何遍历这些图以提取有用的事实。然而,目前可能还不明显的是如何实际解析任意传入的查询并在知识图中查找适当的部分。我们将用第 7 章的大部分内容来介绍如何构建一个端到端语义搜索系统,该系统可以解析查询并集成这些知识图功能。然而,在此之前,我们需要将一些非常具体的关系添加到知识图中,这些关系对搜索引擎特别重要,例如拼写错误、同义词和特定领域的短语。
5.6 总结知识图对域内实体之间的关系进行建模,可以使用已知关系显式构建,也可以从内容中动态提取。开放信息提取,从内容(主题、关系、宾语三元组)中提取事实的过程,可用于学习任意关系(通常会产生嘈杂的数据)或从文本中提取下位词/上位词关系(噪音较小)到明确的文本中。知识图。语义知识图支持对搜索索引中任何内容之间的任意语义关系进行遍历和排名。这使您可以直接将内容用作知识图,除了对内容进行索引之外,无需任何数据建模。可以通过对文档中语义上最有趣的术语和短语进行排名并将它们用作查询来查找其他相关文档并对其进行排名来生成不依赖于用户信号的基于内容的推荐。语义知识图通过支持领域和上下文敏感的查询扩展和重写以及关系发现,可以更好地理解用户意图。长汀这15人以卖黑茶为幌子搞传销,被长汀法院判刑!有你认识的也在卖黑茶吗?
2019年12月30日,长汀县人民法院依法对被告人林某香等15人组织、领导传销活动案一审公开宣判,判处被告人林某香有期徒刑3年,并处罚金20万元;对本案其他14名被告人分别以组织、领导传销活动罪判处免于刑事处罚至2年3个月不等的刑罚及罚金,同时追缴各被告人违法所得。
庭审
法院审理查明
2015年初,被告人林某香在域名为www.5169888的电子商务购物平台,购买了售价为19920元由湖南华莱生物科技有限公司生产的“华莱健”黑茶,并在该网站上注册成为传销队伍“虎狼之师福建小红帽团队”中的黑茶销售代理会员,取得推荐他人购茶入会进而开展传销活动的资格。此后,按照所谓“互助分销”模式,在其位于长汀县汀州豪廷小区的自营茶叶店内发展会员、推广黑茶。2017年8月起,林某香提议和邀集其所属团队的下线人员丘某某、张某某、肖某某、张某某、涂某某、董某某、陈某某、梁某某、刘某某、肖某某、赖某某、赖某某、郭某某等人,以及属于“龙岩团队”的被告人谢某荣商议,决定共同出资成立长汀县香泉文化传播有限公司。同年9月27日,香泉公司在长汀县腾飞经济开发区某服饰公司一号厂房四楼以“华莱健安化黑茶体验馆”的名义挂牌开业。
体验馆开业后,被告人林某香等15名被告人以该体验馆为窝点,分工配合、排班管理,依托www.5169888电子商务购物平台,采取免费品鉴、聊天分享、培训讲座和组织到华莱公司生产基地参观考察、举办“十万得主”感恩答谢招待会等手段,宣称黑茶有降“三高”、祛痛风等功效,并以“超级十万奖金模式”等返利计奖制度为诱饵,鼓吹“一次投资19920元,终身任务就是完成两份推广、两份带动”等快速致富前景,集中引诱和发展社会群众成为传销安化黑茶的会员,同步开展发展下线、培训授课、汇款、兑换电子币以及集中收发物流等传销活动。截至案发,该体验馆运营期间共发展下线人数100余人,其中,被告人范某林发展下线48人;涉案金额200多万元。
法院审理认为
被告人林满香等16名被告无视国家法律,以推销“华莱健”安化黑茶的电子商务经营活动为名发展会员,要求参加者以购买指定数量的产品获得加入资格,并按照推荐人与被推荐人为上下线顺序,组成返利计奖的关系层级,间接以发展人员的数量作为计酬或者返利依据,引诱参加者继续发展他人参加,骗取财物,扰乱社会经济秩序,且组织内部参与传销活动人员在三十人以上、层级在三级以上,其行为均已构成组织、领导传销活动罪。公诉机关指控的事实和罪名成立,应予支持。各被告人犯组织、领导传销活动罪,遂依法作出上述判决。
9长汀县人民法院