#gStore-weekly | ​gAnswer源码分析:后处理

news2024/7/4 4:27:31

gAnswer通过自然语言问题转化成查询图,然后再和图数据库中的RDF图做匹配以生成用于查询的SPARQL语句。在将SPARQL语句应用于gStore查询之前还需要进行修复和聚合,以及一些后处理工作,本文聚焦于此。

// step 0: Node (entity & type & literal) Recognition 
// step 1: question parsing (dependency tree, sentence type)
// step 2: build query graph (structure construction, relation extraction, top-k join)

// step 3: some fix (such as "one-node" or "ask-one-triple") and aggregation
t = System.currentTimeMillis();
AddtionalFix step3 = new AddtionalFix();
step3.process(qlog);

在前几期关于gAnswer的文章中,我们完成了算法前三步的解析,认识了依存分析,节点提取,关系提取,进一步的查询图生成,子图匹配等模块。上面是第四步修复与聚合的入口函数,注释中,举了两个例子,"one-node"单节点查询和"ask-one-triple",之后都会有具体方法的解析。

public HashMap<String, String> pattern2category = new HashMap<String, String>();

public AddtionalFix()
{
    // Some category mappings for DBpedia, try automatic linking methods later. | base form
    pattern2category.put("gangster_from_the_prohibition_era", "Prohibition-era_gangsters");
    pattern2category.put("seven_wonder_of_the_ancient_world", "Seven_Wonders_of_the_Ancient_World");
    pattern2category.put("three_ship_use_by_columbus", "Christopher_Columbus");
    pattern2category.put("13_british_colony", "Thirteen_Colonies");
}

  • 首先在 AddtionalFix
    类内部创建了一个名为 pattern2category
    的哈希映射,用于将查询模式映射到类别。

public void process(QueryLogger qlog)
{
    fixCategory(qlog);
    oneTriple(qlog);
    oneNode(qlog);
    
    //aggregation
    AggregationRecognition ar = new AggregationRecognition();
    ar.recognize(qlog);

    //query type
    decideQueryType(qlog);
}

  • 主方法process
    接受了 QueryLogger
    对象 qlog
    作为参数。在该方法中,依次调用了以下三个方法:fixCategory
    oneTriple
    和 oneNode
    。这是完成fix的三个方法,然后调用 ar.recognize(qlog)
    来进行聚合识别。以及调用了 decideQueryType(qlog)
    来确定查询的类型。

public void fixCategory(QueryLogger qlog)
{
    if(qlog == null || qlog.semanticUnitList == null)
       return;
    
    String var = null, category = null;
    for(SemanticUnit su: qlog.semanticUnitList)
    {
       if(su.centerWord.mayCategory)
       {
          var = "?"+su.centerWord.originalForm;
          category = su.centerWord.category;
       }
    }
    
    if(category != null && var != null)
       for(Sparql spq: qlog.rankedSparqls)
       {
          boolean occured = false;
          for(Triple tri: spq.tripleList)
          {
             if(tri.subject.equals(var))
             {
                occured = true;
                break;
             }
          }
          String oName = category;
          String pName = "subject";
          int pid = Globals.pd.predicate_2_id.get(pName);
          Triple triple =    new Triple(Triple.VAR_ROLE_ID, var, pid, Triple.CAT_ROLE_ID, oName, null, 100);
          spq.addTriple(triple);
       }
}

fixCategory
方法用于修复查询中的类别信息。

  • 遍历 qlog.semanticUnitList
    中的每个语义单元 su
    ,检查其中心词 centerWord
    是否具有可能的类别信息(mayCategory
    标志)。如果有,将中心词的原始形式 originalForm
    作为变量 var
    ,将类别信息 category
    赋给 category

  • 如果 category
    和 var
    在上一步的遍历中得到赋值,遍历 qlog.rankedSparqls
    中的每个 Sparql
    对象 spq
    ,并检查是否已经存在相同变量的三元组。如果不存在相同变量的三元组,将类别信息添加到查询中作为一个新的三元组。

public void oneNode(QueryLogger qlog)
{
    if(qlog == null || qlog.semanticUnitList == null || qlog.semanticUnitList.size()>1)
       return;
    
    Word target = qlog.target;
    Word[] words = qlog.s.words;
    if(qlog.s.sentenceType != SentenceType.GeneralQuestion)
    {
       //1-1: how many [type] are there | List all [type]
       if(target.mayType && target.tmList != null)
       {
          String subName = "?"+target.originalForm;
          String typeName = target.tmList.get(0).typeName;
          Triple triple =    new Triple(Triple.VAR_ROLE_ID, subName, Globals.pd.typePredicateID, Triple.TYPE_ROLE_ID, typeName, null, 100);
          Sparql sparql = new Sparql();
          sparql.addTriple(triple);
          qlog.rankedSparqls.add(sparql);
       }
       //1-2: What is [ent]?
       else if(target.mayEnt && target.emList != null)
       {
          if(words.length >= 3 && words[0].baseForm.equals("what") && words[1].baseForm.equals("be"))
          {
             int eid = target.emList.get(0).entityID;
             String subName = target.emList.get(0).entityName;
             Triple triple =    new Triple(eid, subName, Globals.pd.typePredicateID, Triple.VAR_ROLE_ID, "?"+target.originalForm, null, target.emList.get(0).score);
             Sparql sparql = new Sparql();
             sparql.addTriple(triple);
             qlog.rankedSparqls.add(sparql);
          }
       }
       //1-3: Give me all Seven Wonders of the Ancient World.
       else if(target.mayCategory && target.category != null)
       {
          String oName = target.category;
          String pName = "subject";
          int pid = Globals.pd.predicate_2_id.get(pName);
          Triple triple =    new Triple(Triple.VAR_ROLE_ID, "?"+target.originalForm, pid, Triple.CAT_ROLE_ID, oName, null, 100);
          Sparql sparql = new Sparql();
          sparql.addTriple(triple);
          qlog.rankedSparqls.add(sparql);
       }
    }
    else 
    {
       if(target.mayEnt && target.emList != null)
       {
          //2-2:Was Sigmund Freud married?
          String relMention = "";
          for(Word word: words)
             if(word != target && !word.baseForm.equals(".") && !word.baseForm.equals("?"))
                relMention += word.baseForm+" ";
          if(relMention.length() > 1)
             relMention = relMention.substring(0, relMention.length()-1);
          
          ArrayList<PredicateIDAndSupport> pmList = null;
          if(Globals.pd.nlPattern_2_predicateList.containsKey(relMention))
             pmList = Globals.pd.nlPattern_2_predicateList.get(relMention);
          
          if(pmList != null && pmList.size() > 0)
          {
             int pid = pmList.get(0).predicateID;
             int eid = target.emList.get(0).entityID;
             String subName = target.emList.get(0).entityName;
             Triple triple =    new Triple(eid, subName, pid, Triple.VAR_ROLE_ID, "?x", null, 100);
             Sparql sparql = new Sparql();
             sparql.addTriple(triple);
             qlog.rankedSparqls.add(sparql);
          }
    
          //2-3:Are penguins endangered?
          else
          {
             if(target.position < words.length && pattern2category.containsKey(words[target.position].baseForm))
             {
                String oName = pattern2category.get(words[target.position].baseForm);
                String pName = "subject";
                int pid = Globals.pd.predicate_2_id.get(pName);
                int eid = target.emList.get(0).entityID;
                String subName = target.emList.get(0).entityName;
                Triple triple =    new Triple(eid, subName, pid, Triple.CAT_ROLE_ID, oName, null, 100);
                Sparql sparql = new Sparql();
                sparql.addTriple(triple);
                qlog.rankedSparqls.add(sparql);
             }
          }
       }
       //2-1: Are there any [castles_in_the_United_States](yago:type)
       else if(target.mayType && target.tmList != null)
       {
          String typeName = target.tmList.get(0).typeName;
          String subName = "?" + target.originalForm;
          //System.out.println("typeName="+typeName+" subName="+subName);
          Triple triple =    new Triple(Triple.VAR_ROLE_ID, subName, Globals.pd.typePredicateID, Triple.TYPE_ROLE_ID, typeName, null, 100);
          Sparql sparql = new Sparql();
          sparql.addTriple(triple);
          qlog.rankedSparqls.add(sparql);
       }
    }
}

关于代码中用于识别单节点查询(one-Node query)的逻辑,根据不同情况分成了两大类和六种具体情况:

  • 第一大类:特殊问题(Special question)和祈使句(Imperative sentence),它会处理包含一个节点的查询,并根据不同的情况生成相应的查询三元组,并将其添加到 rankedSparqls 列表中。

    • 1-1:"how many [type] are there" 和 "list all [type]" 这样的问题,首先检查识别的目标词target
      是否可能是一个类型type
      。创建一个三元组,其中实体是变量 subName
      ,谓词是全局定义的表示类型关系的谓词ID(Globals.pd.typePredicateID
      ),宾语是类型名称。

    • 1-2:"What is backgammon?" 和 "What is a bipolar syndrome?" 这样的问题,首先检查识别的目标词target
      是否可能是一个实体entity
      。创建一个三元组,其中实体是变量 subName
      ,谓词是全局定义的表示类型关系的谓词ID(Globals.pd.typePredicateID
      ),宾语是用户查询中的实体描述,以 "?" 加上实体描述("?"+target.originalForm
      )。

    • 1-3:"Give me all Seven Wonders of the Ancient World." 这样的问题,首先检查识别的目标词target
      是否可能是一个类别category
      。创建一个三元组,其中实体是变量 "?"+target.originalForm
      ,谓词是特定分类对应的谓词ID,宾语是用户查询中的特定分类(oName
      )。

  • 第二大类:一般问题(General question),根据目标词target
    是否可能是实体mayEnt
    和是否有实体列表emList
    ,进行不同的处理。

    • 2-1:"Are there any [castles_in_the_United_States]"这样的问题,首先检查识别的目标词target
      是否可能是一个类型type
      ,需要检查特定类型的实体是否存在。创建一个三元组,主语是一个变量(由 subName
      指定),谓词是一个特定的谓词(由 Globals.pd.typePredicateID
      指定),宾语是一个特定实体的类型(由 typeName
      指定)。

    • 2-2:"Was Sigmund Freud married?" 这样的问题,首先检查识别的目标词target
      是否可能是一个实体entity
      ,用户查询可能是关于特定实体的事实。创建一个三元组,其中实体是变量 ?x
      ,谓词是获取的谓词,宾语是实体名。

    • 2-3:"Are penguins endangered?" 这样的问题,首先检查识别的目标词target
      是否可能是一个实体entity
      ,用户可能在询问特定实体的类别。创建一个三元组,其中实体是实体名,谓词是获取的谓词,宾语是类别名。

这些情况将影响代码中单节点查询的处理方式。

public void oneTriple (QueryLogger qlog)
 {
  if(qlog == null || qlog.semanticUnitList == null)
   return;
  
  if(qlog.s.sentenceType == SentenceType.SpecialQuestion)
  {
   Word[] words = qlog.s.words;
   if(qlog.semanticUnitList.size() == 2)
   {
    Word entWord = null, whWord = null;
    for(int i=0;i<qlog.semanticUnitList.size();i++)
    {
   if(qlog.semanticUnitList.get(i).centerWord.baseForm.startsWith("wh"))
      whWord = qlog.semanticUnitList.get(i).centerWord;
     if(qlog.semanticUnitList.get(i).centerWord.mayEnt)
      entWord = qlog.semanticUnitList.get(i).centerWord;
    }
    // 1-1: (what) is [ent] | we guess users may want the type of ent.
    if(entWord!=null && whWord!= null && words.length >= 3 && words[0].baseForm.equals("what") && words[1].baseForm.equals("be"))
    {
     int eid = entWord.emList.get(0).entityID;
     String subName = entWord.emList.get(0).entityName;
     Triple triple = new Triple(eid, subName, Globals.pd.typePredicateID, Triple.VAR_ROLE_ID, "?"+whWord.originalForm, null, entWord.emList.get(0).score);
     Sparql sparql = new Sparql();
     sparql.addTriple(triple);
     qlog.rankedSparqls.add(sparql);
    }
   }
  }
 }
}

oneTriple
方法用于处理在句子中能识别三元组但没有合适关系的情况。

  • 检查句子类型是否为特殊问题(SentenceType.SpecialQuestion
    )。如果是,继续检查是否识别出了两个语义单元(semanticUnitList.size() == 2
    )。

  • 如果符合条件,尝试构建一个三元组。这里主要处理了一种情况:

    • 遍历语义单元,根据语义单元的属性,识别实体词和疑问词。

    • 类似 "What is [ent]?" 这样的问题。根据识别到的实体词(entWord
      )和疑问词(whWord
      ),构建一个以实体为主语、类型为谓词、疑问词为宾语的三元组,然后将这个三元组添加到 SPARQL 查询列表(qlog.rankedSparqls
      )中。

// deduplicate in SPARQL
    for(Sparql spq: rankedSparqls)
       spq.deduplicate();
    
    // Sort (descending order).
    Collections.sort(rankedSparqls);
    qlog.rankedSparqls = rankedSparqls;
    System.out.println("number of rankedSparqls = " + qlog.rankedSparqls.size());
    
    // Detect question focus.
    for (int i=0; i<qlog.rankedSparqls.size(); i++) 
    {
       // First detect by SPARQLs.
       Sparql spq = qlog.rankedSparqls.get(i);
       String questionFocus = QuestionParsing.detectQuestionFocus(spq);
       
       // If failed, use TARGET directly.
       if(questionFocus == null)
          questionFocus = "?"+qlog.target.originalForm;
       
       spq.questionFocus = questionFocus;
    }
             
    return qlog;
} 

最后,将得到的SPARQLS查询列表进行去重、排序和问题焦点的检测等后处理。返回包含处理后的信息的 QueryLogger
对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1230168.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Sqlserver 多行合并为一行

多行合并为一行 表结构 子表结构如下&#xff1a; 父表结构如下&#xff1a; 由图可以看出子表和父表是通过父表ID进行关联的。 我们要实现的效果如下&#xff0c;查询父表数据的同时&#xff0c;增加一列来展示父表下子商品信息。 完整代码如下 select top {0} * from (…

java基础练习缺少项目?看这篇文章就够了(上)!

公众号&#xff1a;全干开发 。 专注分享简洁但高质量的动图技术文章&#xff01; 项目概述 本教程适合刚学习完java基础语法的同学&#xff0c;涉及if语句、循环语句、类的封装、集合等基础概念&#xff0c;使用大量gif图帮助读者演示代码操作、效果等&#xff0c;是一个非常…

【LeetCode刷题-字符串】--6.N字形变换

6.N字形变换 方法&#xff1a;使用二维矩阵模拟 根据题意&#xff0c;当在矩阵中填写字符时&#xff0c;会向下填写r个字符&#xff0c;然后向右继续填写r - 2个字符&#xff0c;最后回到第一行&#xff0c;因此Z字形变换的周期是t r r - 2 2r - 2&#xff0c;是|/,每个周期…

Cesium点位弹窗

1.弹窗没法向加入点位一样加入到地图内部&#xff0c;entity没法实现 2.使用绝对定位&#xff0c;将地图组件通过定位加入到地图上&#xff0c;注意弹窗层级一定在地图上 3.通过判断点击位置是否是点位来获取entity信息&#xff0c;将信息显示在弹窗 4.将点击处点位的经纬度转为…

在Vue3中使用Element-Plus分页(Pagination )组件

开发过程中数据展示会经常使用到&#xff0c;同时分页功能也会添加到页面中。 记&#xff1a;在Vue3中使用Element-Plus分页组件与表格数据实现分页交互。 开始实现 引入表格和分页组件的H5标签。 <strong>Element-Plus分页组件使用</strong> <div><el-t…

视频监控管理平台EasyCVR告警查询拖动条无法显示,该如何解决?

视频汇聚/视频云存储/集中存储/视频监控管理平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;实现视频资源的鉴权管理、按需调阅、全网分发、云存储、智能分析等&#xff0c;视频智能分析平台EasyCVR融合性强、开放度…

linux镜像的下载,系统下载(个人使用)

文章目录 一、系统之家二、国内镜像源三、Centos官网四、安装成功截图五、镜像类型的区别参考文档 一、系统之家 系统之家官网 二、国内镜像源 下载镜像地址&#xff1a; 1、官网地址&#xff1a;https://www.centos.org/ 2、阿里镜像站&#xff1a;https://mirrors.aliyu…

广西柳州机械异形零部件三维扫描3D抄数全尺寸测绘建模-CASAIM中科广电

一、背景介绍 复杂机械异形零部件具有不规则的形状和复杂的结构&#xff0c;给生产制造带来了很大的检测难度。为了确保零部件的制造质量和精度&#xff0c;需要对零部件进行全面的尺寸检测和分析。 CASAIM三维扫描仪在机械异形零部件全尺寸检测应用可以实现对机械异形零部件…

ATFX汇市:欧元区10月CPI年率终值不变,EURUSD逼近1.1000心理关口

ATFX汇市&#xff1a;据欧盟统计局11月17日发布的数据&#xff0c;欧元区10月名义CPI年率终值2.9%&#xff0c;与10月末公布的初值持平。欧央行对通胀率的长期调控目标为2%左右&#xff0c;10月份名义CPI年率已经非常接近目标范围&#xff0c;欧央行继续加息的紧迫性降低。10月…

java基础练习缺少项目?看这篇文章就够了(下)!

公众号&#xff1a;全干开发 。 专注分享简洁但高质量的动图技术文章&#xff01; 回顾 在上节内容中&#xff0c;我们实现了用户开户的功能createAccount public void start(){System.out.println("欢迎您进入到了ATM系统");System.out.println("1、用户登录&…

思伟老友记 | 厦门路桥翔通海砼建材有限公司与思伟软件携手走过23年

23年 感恩相伴 携手成长 2001年-2023年&#xff0c;厦门路桥翔通海砼建材有限公司已携手上海思伟软件有限公司走过23年。从最初的半手动生产模式到如今的自动生产一体化系统&#xff0c;海砼公司通过思伟软件生产混凝土累计超过1000万m&#xff0c;思伟软件则借助海砼公司的实…

拜托!佛系点,你只是给社区打工而已

社区人到年底了各种要写的东西很烦啊&#xff01;突然看到这个&#xff0c;真的谢谢啊&#xff01; 家人们谁懂啊&#xff1f;&#xff01;&#xff01;平时写个东西起码两三天&#xff0c;试了一下这东西&#xff01;输入需求&#xff0c;一键生成&#xff0c;写好了&#xf…

数据结构与算法编程题5

从有序表中删除重复元素&#xff0c;使表中所有元素值均不相同。 #include <iostream> using namespace std;typedef int ElemType; #define Maxsize 100 #define OK 1 #define ERROR 0 typedef struct SqList {ElemType data[Maxsize];int length; }SqList;void Init_…

斐波那契数列,剑指offer,力扣

目录 题目地址&#xff1a; 我们直接看题解吧&#xff1a; 解题方法&#xff1a; 难度分析&#xff1a; 审题目事例提示&#xff1a; 解题思路&#xff08;动态规划&#xff09;&#xff1a; 代码实现&#xff1a; 补充说明&#xff1a; 代码&#xff08;优化&#xff09;&…

常用 API 异常

常用 API & 异常 对之前那篇 API 文章的补充学习 1.API 1.1 API概述【理解】 什么是API ​ API (Application Programming Interface) &#xff1a;应用程序编程接口 java中的API ​ 指的就是 JDK 中提供的各种功能的 Java类&#xff0c;这些类将底层的实现封装了起来&am…

Redis ACL 规则说明

Redis ACL 规则说明 前情回顾ACL 定义规范启用和禁用用户允许和禁止调用命令允许或禁止访问某些 Key为用户配置有效密码 ACL 命令说明 前情回顾 上一篇文章 我们整体性的介绍了 Redis 的 ACL&#xff0c;我们来回顾下 ACL 的两种配置方式。 redis 使用 acl 有两种方式可以配置…

【从入门到起飞】JavaSE—带你了解Map,HashMap,TreeMap的使用方法

&#x1f38a;专栏【Java基础】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【The truth that you leave】 &#x1f970;欢迎并且感谢大家指出我的问题 文章目录 &#x1f33a;双列集合的特点&#x1f384;Map&#x1f354;Ma…

inBuilder低代码平台新特性推荐-第八期

今天来给大家带来的是inBuilder低代码平台特性推荐系列第八期——定时任务&#xff01; inBuilder计划任务框架支持快速开发&#xff0c;任务开发完成后&#xff0c;只需发布成bean&#xff0c;并通过配置界面绑定所需触发器&#xff0c;即可到点触发。 一、 概念介绍 定时任…

Java的IO流-打印流

打印流 PrintStream public void println&#xff08;&#xff09;自动换行 PrintWriter package com.itheima.println;import java.io.FileInputStream; import java.io.PrintStream; import java.io.PrintWriter;public class Test2 {public static void main(String[] arg…