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

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
对象。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在电脑PC端可以分类记笔记的软件选择哪个?

选择用电脑来记录笔记是比较便捷的&#xff0c;电脑屏幕比较大&#xff0c;操作起来比较便捷。但是很多人用电脑来记录笔记&#xff0c;通常会使用电脑上自带的记事本、文档记事工具来整合笔记&#xff0c;打开文档记事本类的软件&#xff0c;密密麻麻的文字呈现出来。 选择用…

HarmonyOS ArkTS开发语言介绍(三)

1 引言 Mozilla创造了JS&#xff0c;Microsoft创建了TS&#xff0c;Huawei进一步推出了ArkTS。 从最初的基础的逻辑交互能力&#xff0c;到具备类型系统的高效工程开发能力&#xff0c;再到融合声明式UI、多维状态管理等丰富的应用开发能力&#xff0c;共同组成了相关的演进脉…

宽瞬时带宽放大器SKY66051-11、SKY66052-11、SKY66041-11、SKY66317-11(RF)适用于通讯网络

一、2300至2700 MHz宽瞬时带宽高增益线性驱动放大器&#xff1a;SKY66051-11 SKY66051-11是一款具有高增益和高线性度的宽瞬时带宽、完全输入/输出匹配驱动放大器。通过使用外部元件&#xff0c;增益可在30dB至36dB范围内调整。紧凑型33 mm PA专为工作频率为2300至2700 MHz的4…

JDY蓝牙注意事项

波特率设置&#xff1a;9600&#xff0c;不接受115200&#xff0c;或者38400. 不同于WiFi测试&#xff0c;jdy蓝牙不接受AT"指令&#xff0c;可以使用“ATVERSION"指令测试 安信可公司的那个蓝牙指令在这里没有用&#xff0c;不知道是不是生产的公司不一样

参加了南京 GDG 活动:这些精彩的技术讨论,值得与你分享~

一直以来发的文章大都是技术的&#xff0c;这次和大家聊点简单点的。 密集输出这几年&#xff0c;因为疫情没能在线下和大家碰面&#xff0c;去年又因为时间原因浪费了 Google IO China 门票。所以&#xff0c;今年的南京本地的 GDG DevFest 2023 活动一经上线&#xff0c;就报…

【EI会议征稿】第三届电子信息工程与数据处理国际学术会议(EIEDP 2024)

第三届电子信息工程与数据处理国际学术会议&#xff08;EIEDP 2024&#xff09; 2024 3rd International Conference on Electronic Information Engineering and Data Processing Welcome to the official website of 2024 3rd International Conference on Electronic Infor…

Windows系统搭建VisualSVN服务并结合内网穿透实现公网访问

目录 前言 1. VisualSVN安装与配置 2. VisualSVN Server管理界面配置 3. 安装cpolar内网穿透 3.1 注册账号 3.2 下载cpolar客户端 3.3 登录cpolar web ui管理界面 3.4 创建公网地址 4. 固定公网地址访问 总结 前言 SVN 是 subversion 的缩写&#xff0c;是一个开放源…

本地搭建Stackedit Markdown编辑器结合内网穿透实现远程访问

文章目录 1. docker部署Stackedit2. 本地访问3. Linux 安装cpolar4. 配置Stackedit公网访问地址5. 公网远程访问Stackedit6. 固定Stackedit公网地址 StackEdit是一个受欢迎的Markdown编辑器&#xff0c;在GitHub上拥有20.7k Star&#xff01;&#xff0c;它支持将Markdown笔记保…

2023年【起重机司机(限桥式起重机)】证考试及起重机司机(限桥式起重机)模拟考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 起重机司机(限桥式起重机)证考试是安全生产模拟考试一点通生成的&#xff0c;起重机司机(限桥式起重机)证模拟考试题库是根据起重机司机(限桥式起重机)最新版教材汇编出起重机司机(限桥式起重机)仿真模拟考试。2023年…

API接口接入1688电商数据平台获取商品详情数据示例

1688电商数据平台是一个提供海量商品信息的数据平台&#xff0c;通过API接口可以方便地获取商品详情数据。以下是一个示例&#xff0c;演示如何接入1688电商数据平台&#xff0c;获取商品详情数据。 步骤一&#xff1a;注册1688账号并获取API权限 首先需要在1688电商数据平台…

大数据-之LibrA数据库系统告警处理(ALM-12057 元数据未配置周期备份到第三方服务器的任务)

告警解释 系统安装完成后会检查元数据是否有周期备份到第三方服务器的任务&#xff0c;然后每1小时会检查一次。如果元数据未配置周期备份到第三方服务器的任务&#xff0c;将发送严重告警。 在用户创建元数据周期备份到第三方服务器的任务后&#xff0c;告警消除。 告警属性…

【以图会意】操作系统的加载流程

声明&#xff1a;本图为博主方便自己记忆理解&#xff0c;诸多疏漏望请博友理性观看&#xff01;如有错误不足恳请指正。 首先&#xff0c;操作系统是一段程序&#xff0c;他保存在ROM中&#xff0c;在开机时&#xff0c;CPU被激活&#xff0c;首先将IR置为BIOS&#xff08;Bas…

【Reading Notes】

文章目录 中文AA 或 AAAAAAAAAAA&#xff0c;BBBBAAAA&#xff0c;BBBB&#xff0c;CCCCAAAA&#xff0c;BBBB&#xff0c;CCCC&#xff0c;DDDDAAAAAAAAAA&#xff0c;BBBBBAAAAA&#xff0c;BBBBB&#xff0c;CCCCC&#xff08;肆&#xff09;AAAAA&#xff0c;BBBBB&#xf…

【C/C++】递归算法

信封 某人写了n封信和n个信封&#xff0c;如果所有的信都装错了信封。求所有的信都装错信封共有多少种不同情况 #include <iostream> using namespace std; const int N 30; int n; long f[N];int main() {scanf("%d", &n);f[1] 0, f[2] 1;for (int …

SPDK NVMe-oF target多路功能介绍

基本概念 SPDK NVMe-oF target multi-path是基于NVMe协议的multi-path IO和namespace sharing功能。 NVMe multi-path IO指的是两个或多个完全独立的PCI Express路径存在于一个主机和一个命名空间。 而namespace 共享是两个或多个主机使用不同的NVMe控制器访问一个shared na…

键盘控制ROS车运动

键盘控制ROS车运动 上位机 使用pyseria库与stm32单片机进行通信控制 #!/usr/bin/env python # -*- coding: utf-8 -*import sys, select, termios, tty import serialmsg """ ---------------------------w a x ds w : x a : y s : -x …

基于JavaWeb的智慧停车管理系统设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。你想解决的问题&#xff0c;今天给大家介绍…

右键菜单和弹出菜单的区别

接触windows开发10年了&#xff0c;一直以为"右键菜单"和"弹出菜单"是不同的。 最近刚刚发现&#xff0c;这两种菜单在定义的时候和消息循环处理程序中并没有什么不同&#xff0c;区别只是在于windows底层显示方式。 如下是右键菜单的显示方式&#xff1…

42、element表格内容溢出自动往上滚动,鼠标移入停止滚动,溢出继续滚动

vue模块&#xff0c;添加ref属性 <v-table ref"rollTable" style"margin: 0!important;" :loading"TBloading" :isIndex"true" :tableData"tableData":tableHead"tableHead":paginationShow"false"…

海康威视综合安防管理平台任意文件上传

系统介绍 HIKVISION iSecure Center综合安防管理平台是一套“集成化”、“智能化”的平台&#xff0c;通过接入视频监控、一卡通、停车场、报警检测等系统的设备&#xff0c;获取边缘节点数据&#xff0c;实现安防信息化集成与联动&#xff0c;公众号&#xff1a;web安全工具库…