文本检索 关键词检索和

问候,


介绍


本周,我们开始构建Query对象。 查询可以检索部分文本

从图书馆。 我不希望用户自己建立查询,因为用户

犯错误。 取而代之的是,图书馆提供给用户一个简单的查询

请求参数。 库是这样的:

public Query getQuery(String query) throws QueryException { 
    return new QueryTxt(this, query);
}


用户输入一个字符串,然后再次获得一个查询。 但是什么是查询?

继续阅读。


查询界面


查询又是一个接口,它看起来像这样:

public interface Query { 
    public int size();
    public List<BookMark> result();
}


size()方法返回具有正数的结果(段)数

与查询文字匹配。 result()方法返回书签列表

代表所有匹配的段落。

在内部,查询子系统使用此接口的扩展:

interface InternalQuery extends Query { 
    public BitSet evaluate();
}


如您所见,该界面将以前的界面扩展为一个

方法。 该validate()方法应该评估(原文如此)该查询。 这个

接口不是公共接口,因此用户只知道查询

接口本身。

result()接口方法的实现调用了validate()

方法仅一次; 所以无论result()方法本身是多少次

调用后,结果已经是“已知的”并且查询不需要

重新评估。


查询内部


简单查询只是一个简单的文本单词。 这个词在

库的WordMap(请参阅上一节),并使用BitSet

指出哪些段落包含该词:

private BitSet makeBitSet(int[] p) { 
    BitSet bs= new BitSet(); 
    for (int i= 0; i < p.length; bs.set(p[i++])); 
    return bs;
}


给定int数组,这些数组代表以下段落的索引:

一个单词出现时,将构造一个BitSet并将相应的位设置为1。

如果您查看BitSet API文档,就会发现BitSet非常有用

方便工作:他们可以使用一种方法来操纵整个BitSet

调用,即它们可以“和”和“或”两个BitSet以及整个范围

可以设置或重置BitSet中的位。

那么,为什么我不首先在该WordMap中使用BitSet? 原因是,

BitSet可能比段落索引的简单数组大得多; 假设

仅在第65,000段中出现一个字。 一个BitSet将花费+-65,000位

(大约8KB),而一个元素int数组仅存储索引

数字65,000将采用单个32位int。

查询对象涉及的大多数工作是操纵BitSet,因为

他们很快就可以操纵。


查询语言


传递给库的字符串具有某种语法,即

查询。 这是一种非常简单的语言:最简单的查询是单个

单词如上一段所示。

查询可以在逻辑上“与”和“或”在一起。 “和”运算符具有

优先级高于“或”运算符,例如查询:

耶稣与上帝 魔鬼

列出其中出现耶稣和上帝两个单词的段落,或者只是

魔鬼这个词,或全部三个词。

请注意,符号“&”和“ |” 代表“和”和“或”运算符。

子查询可以通过用括号“(”和“)”括起来进行分组。

例如,以下查询给出的结果与上一个查询不同

查询确实:

耶稣与(上帝|恶魔)

如果这些段落包含耶稣这个词,则它们是查询的结果

连同“上帝或魔鬼”一词或其中两个词一起使用

可以在查询前面加上感叹号“!”来取反查询,因此

以下查询:

耶稣&!(上帝|魔鬼)

返回那些包含耶稣一词但不包含任何词的段落

神还是魔鬼。

'and'运算符还有很多:如果直接跟一个数字

(非负整数)该数字被视为“接近”; 这是

一个例子:

耶稣&10神

此查询返回包含(或两个词)的所有段落

耶稣或上帝,只有在“接近”十个段落中的另一个段落

包含另一个词。 假设第n段包含耶稣一词; 这个

如果段落之一,则该段落仅是结果的一部分

n-10,n-9,... n-1,n,n + 1,... n + 9,n + 10

包含上帝一词。 该查询是可交换的,因此查询:

神与十耶稣

返回相同的结果(如果有)。 请注意,“&”之间不允许有空格

符号和数字。 空格是可选的,因此上一个查询可以具有

被写为:

神与耶稣

如果单词包含前导数字,则必须在数字之间使用空格

第二个单词(如果它包含前导数字)。 如果号码不存在

假定值为0(零),即和查询的两个操作数都必须出现

仅在同一段落中。

最后一个查询语言元素是正则表达式。 正则表达式

查询中的格式如下:

= <delimeter> <正则表达式> <delimeter>

接下来的查询使用正则表达式,并且所有查询的结果相同:

= / esus /

= AesusA

=%esus%

前导和尾数必须相等,并且不能用于

正则表达式本身。 对于也阅读我的编译器的读者

文章系列,以下Backus Naur表示法描述了正式语法

查询语言:

查询=和查询{| 和查询} *

and-query =一元查询{&number? 一元查询} *

一元查询=(查询)| ! 一元查询| = delim正则表达式delim | 字

number =任何非负整数

regexp =任何正则表达式

delim =任何字符

单词=任意字母或数字序列


查询实现


查询子系统形成了一些类的层次结构。 你们都看过

接口已经存在(请参见上文)。 层次结构如下所示:

Query
   |
   +---- InternalQuery
                 |
                 +------- AbstractQuery
                 |                |
                 |                +------- QueryAnd
                 |                |
                 |                +------- QueryNot
                 |                |
                 |                +------- QueryOr
                 |                |
                 |                +------- QueryRex
                 |
                 +------- QueryTxt


QueryTxt类是查询编译器; 如您在开始时所见

本文的一部分,这是图书馆拥有的类

向用户分发查询。

所有其他具体类都从AbstractQuery类扩展而来,

记账的轨迹,例如makeBitSet()方法(参见上文)是

在此类中实现的方法。

其他类仅实现自己的“ evaluate()”方法。 编译时

成功的结果将是一个InternalQuery对象。 对象传递给

用户实际上是一个QueryTxt对象。 当用户调用任何方法时

在Query接口中定义的QueryTxt对象将调用委托给

内部查询对象,它是编译阶段的结果。

注意,简单的“单词”查询没有特殊的类。 这是处理

通过一个不需要“或”的QueryOr对象,只需为单个对象构建一个BitSet

查询中的单词。


文本


除QueryRex外,所有查询均不需要实际扫描实际

文字:他们都使用存储在库本身中的WordMap并构建

相应的BitSet。

就处理时间而言,QueryRex是一个“昂贵”的查询:它需要

从书签中检索实际文本并匹配正则表达式

反对这个文本。 使用的文本是BookMark的toString()的结果

方法。

此方法不仅返回段落文本,还返回组名,

书籍,章节和相关段落编号。 (请参阅上一篇文章

部分),因此QueryRex也可以搜索并找到这些名称。


结束语


下周,我将为您指向两个包含压缩文本的.zip文件

詹姆斯国王圣经和荷兰史泰登Vertaling圣经。 我会附上所有

带有下一部分文章的源代码。

您可以解压缩.zip文件,编译源代码,然后开始经营业务

然后:建立一个资料库并查询结果。 下周我会详细介绍

说明。

Prometheuzz不仅为我提供了荷兰史泰登Vertaling的全文,

圣经,但他还为我提供了两个.zip文件的磁盘空间。 我自己的ISP是

scrooge,我自己不能托管这两个文件,所以我非常感谢Prometheuzz

对于他的报价:非常感谢,我欠你一杯啤酒。

我希望下周见

亲切的问候,

乔斯

翻译自: https://bytes.com/topic/java/insights/691601-text-retrieval-systems-6-queries

文本检索 关键词检索和