确定一个句子是否是一个查询

时间:2010-11-02 23:37:48

标签: nlp

如何检测搜索查询是否采用问题的形式?

例如,客户可能会搜索“我如何跟踪订单”(请注意没有问号)。

我猜大多数直接问题都符合特定的语法。

非常简单的猜测方法:

START WORDS = [who, what, when, where, why, how, is, can, does, do]

isQuestion(sentence):
  sentence ends with '?'
  OR sentence starts with one of START WORDS

START WORDS列表可能会更长。范围是一个网站搜索框,所以我想这个列表不需要包含太多单词。

是否有一个库可以比我简单的猜测方法做得更好?我的方法有什么改进吗?

6 个答案:

答案 0 :(得分:17)

另请参阅:How to find out if a sentence is a question (interrogative)?

我对这个问题的回答:

在问题的语法分析中(通过像nltk这样的工具包获得),正确的结构将采用以下形式:

(SBARQ (WH+ (W+) ...)
       (SQ ...*
           (V+) ...*)
       (?))

因此,使用任何可用的语法分析器,具有嵌入式SQ(可选)的SBARQ节点的树将指示输入是一个问题。 WH +节点(WHNP / WHADVP / WHADJP)包含问题词干(who / what / when / where / why / how),SQ包含倒置短语。

即:

(SBARQ 
  (WHNP 
    (WP What)) 
  (SQ 
    (VBZ is) 
    (NP 
      (DT the) 
      (NN question)))
  (. ?))

当然,有很多先行条款会导致解析中的错误(可以解决),以及写得很糟糕的问题。例如,这篇文章的标题“如何判断一个句子是一个问题?”将有一个SBARQ,但不是SQ。

答案 1 :(得分:15)

你需要一种更先进的语言分析形式才能实现这一目标。需要证明吗?好...

  

是雌鹿吗?

     

如果有遗嘱,有办法。

     

到时候,我会跳!

     

为什么不。我没有任何裸麦粉粗面包。

答案 2 :(得分:8)

找出一个句子是否是一个问题不是一个最容易的任务,因为人们提问的方式很多,其中很多都不遵循语法规则。因此很难找到一个好的检测规则集。在这种情况下,我会去机器学习并使用带注释的文本语料库训练算法(创建语料库并选择一个特征集可能需要一些时间)。基于机器学习的识别应该比基于规则的方法更好地回忆。这是一步一步的说明:

  1. 手动创建列车数据集:获取带注释的信息 - 如果是或不是信息 - 文本集合或自己创建这样的语料库(它应该是100多个文档,许多问题不能是直截了当的问题)
  2. 找出最重要的特征 - 提取部分演讲,5W1H(什么,哪个,......,如何),在每个句子中获得动词的位置,以及其他可用于识别的内容一个问题
  3. 根据提取的信息为每个特征句子创建一个向量(您需要同时使用正面和负面示例),例如

    |具有 ? |第二个位置的动词|有5W1H |句子中的第一个位置是5W1H | ...... |句子长度|是一个问题|

  4. 使用train a machine learning algorithm向量,例如MaximumEntropy,SVM(您可以使用WekkaKnime

  5. 使用经过训练的算法进行问题识别。

  6. 如果需要(新问题示例),请重复步骤。

答案 3 :(得分:7)

要识别问题句子的起始词,你应该通过一个大型文本语料库来查找以?结尾的句子,并找出你在那些中找到的最常见的起始词。

你错过了一些想到的东西包括WHICH,AM,ARE,WAS,WERE,MAY,MIGHT,CAN,COULD,WILL,SHALL,WOULD,SHOULD,HAS,HAVE,HAD和DID。或许也可以和WHEN一起去。还要考虑IN,AT,TO,FROM和ON,加上UNDER和OVER。所有这些都取决于您拥有的查询系统类型以及您希望为用户提供的自然语言查询的自由度。

同样,你应该检查一下人们已经在同一个灯光下做出的所有查询,找出他们的哪些问题实际?结尾,以帮助识别类似的不要。

应该找到很多疑问句;当务之急也是可能吗?

根据您想要获得的花哨程度,您可以考虑使用Wordnet之类的东西作为词性标注的开头。它主要用于同义词集,包括hypernym,hyponym,holonym和meronym信息,但我相信它还会包含您正在寻找的其他信息。

维基百科在question answeringnatural language search engines上有几篇文章。两者都有您可能会关注的参考。您也可以浏览这些PDF文件:

最后,来自麻省理工学院的START Natural Language Question Answering System似乎很有趣。

答案 4 :(得分:7)

为了支持JohnFx的答案,情况变得更糟。以下是明确的问题:

  • 您有任何问题
  • 这个答案是否足够
  • 一个问题,那是什么

然后你会发现用户开始输入以下类型的查询:

  • 我想知道有什么问题。

这甚至是一个问题吗?从语法上讲,不,但它确实值得一个很容易被称为答案的回复。 (这些类型的查询可能很常见,具体取决于您的用户群。)

底线:如果你不打算以特殊的,语言上复杂的方式处理问题(例如使用自然语言生成构建直接答案),识别它们可能甚至不是很有趣。从查询中挑选正确的关键字可能会更有价值。

答案 5 :(得分:0)

我为此付出了努力……我的目标是做一些不需要额外库的轻量级的事情,并使每个开发人员都能够控制一些必要的元素,例如使用负收缩来填充某些字符仅作为第一个单词的位置,并允许使用常见的问题元素。我创建了两个函数,当您从Angular6 HTML页面中传递一个值时,它对我的​​大多数情况都起到了很好的作用...

我不将“不要”作为首字母,因为它可以是一个问题的多次陈述。你不觉得吗?

角度HTML:

          <input matInput type="text" placeholder="{{Prompt}}" [(ngModel)]="value">

.ts函数:

  isQuestion(sentence: string = this.value){
    var q_elements : string[] = ["who", "what", "when", "where", "why", "how", "?"];
    var q_starters : string[] = ["which", "won't", "can't", "isn't", "aren't", "is", "do", "does", "will", "can", "is"];
    var temp = sentence.toLowerCase();
    var padChars : string[] = ["?", "-", "/"];
    var i : number = 0;
    for (i=0; i < padChars.length; i++) {
      temp = this.padChar(temp, padChars[i]);
    }
    var splitted = temp.split(" ");
    // console.log(splitted);
    if (q_starters.includes(splitted[0])) {
      // console.log('found a question with a starter');
      return true;
    } else {
      return q_elements.some(function (v) {
        return splitted.indexOf(v) >= 0;
      });
    }
  }

  padChar(myString : string, myChar : string) {
    var position = myString.indexOf(myChar);
    var output : string = myString;
    while(position > 0 && position < output.length) {
      if (output.charAt(position - 1) != " ") {
        output = [output.slice(0, position), " ", output.slice(position)].join('');
        position = output.indexOf(myChar, position);
      }
      if (position + 1 < output.length) {
        if (output.charAt(position + 1) != " ") {
          output = [output.slice(0, (position + 1)), " ", output.slice(position + 1)].join('');
          position = output.indexOf(myChar, position);
        }
      }
      position = output.indexOf(myChar, position + 1);
    }
    return output;
  }