文本检索系统-4B:图书馆

问候,

欢迎回来; 上面我们讨论了Library类的外围设备:loading

并保存它的实例化,然后在BookMark接口中保存。

本文的这一部分将进一步讨论Library类的内部。

再次分段

上一篇文章的一部分显示了Sections是如何工作的,即组Section所指

预订科目,一本书科目指的是科目章节,后者指的是

到文字段落。

在Library类中实现了一些方法,可以处理所有

区段操纵。 这是前两个; 他们找到一个部分的索引

在给定Section名称的Section数组中:

 
private int getIndex(Section[] sections, String name) { 
    return getIndex(sections, name, 0, sections.length);
} 
private int getIndex(Section[] sections, String name, int lo, int n) { 
    for (int i= lo; n-- > 0; i++)
        if (sections[i].getName().equals(name)) return i; 
    return -1;
} 
第一种方法在给定的Sections数组中找到Section的索引

本节的名称。 它将工作委托给第二种方法

采用最低索引号形式的索引间隔为

考虑和数组中相邻节的数量。

这几乎不是火箭科学,但是我们仍然需要这些方法。 下一个

方法更聪明:假设我们要查找给定书的索引

一章的绝对索引号; 以下方法可以处理所有问题:


private int getIndex(Section[] section, int index) { 
    for (int lo= 0, hi= section.length-1; lo <= hi; ) {
        int mid= (lo+hi)>>>1;
        int ilo= section[mid].getIndex();
        int ihi= ilo+section[mid].getTotal(); 
        if (ilo <= index && ihi > index) return mid;
        if (ihi <= index) lo= mid+1;
        else              hi= mid-1;
    } 
    return -1;
} 
给定一个Sections数组和一个索引号,此方法将应用二进制

在数组中搜索并找到“包容”部分的索引

所需索引,即Section包含作为参数传入的索引。

例如,《国王詹姆斯圣经》包含1352个章节和36133个段落。

给定一个段落编号,此方法可以找到相应的章节

在2log(1352)操作中,最多少于11个搜索操作。

鉴于

章节等的索引,因为书籍比那里少得多

是章节,而书籍则少得多。

信不信由你,但上述方法是唯一的“智能”

需要并在Library类中实现。

简单统计

库对象也可以生成简单的统计信息以及

实施起来非常简单; 他们来了:


public String getTitle() { return title; } 
public int getGroupSize() { return groups.length; }
public int getBookSize() { return books.length; }
public int getChapterSize() { return chapters.length; }
public int getParagraphSize() { return paragraphs.length; }
public int getWordSize() { return words.length; }
public int getIndexSize() { return wordMap.size(); }
public int getOccurrences(String word) { 
    int[] paragraphs= wordMap.get(word); 
    return (paragraphs == null)?0:paragraphs.length;
} 
第一种方法实际上不是统计类型的方法,但我将其包括在内

无论如何。 其他方法简单地返回各种数组的长度,并且

WordMap在文本检索功能中起着至关重要的作用。

这是我实现的另一种简单方法:


public int[] getIndexes(String word) {  
    int[] paragraphs= wordMap.get(word); 
    return (paragraphs == null)?null:Arrays.copyOf(paragraphs, paragraphs.length);
} 
该方法返回出现某个单词时所有索引值的副本。

因为我不希望任何调用者返回原始数组的副本

不小心破坏了原始数组中的值。 有一个来电者

我相信:我; *啊*,所以特别是对我来说,我写了这个方法:


int[] getWordIndexes(String word) { return wordMap.get(word); } 
稍后,当我们要实现更多精美的文本时,我需要那种方法

检索功能。 请注意,这不是公共方法。

文字解码

如前一篇文章所述,文本是经过压缩和编码的。

段落字符串不是文字文本,而只是其表示形式。

下面的(非公共!)方法再次检索实际文本,

编码的段落字符串:


String decompress(String text) { 
    StringBuffer sb= new StringBuffer();  
    for (int i= 0, n= text.length(); i < n; i++) { 
        char c= text.charAt(i); 
        if (c < 0x20) 
            sb.append(punctuation[0].charAt(c)).append(' ');
        else if (c < 0x100)
                sb.append(punctuation[1].charAt(c&0x1f));
        else {
            sb.append(words[c-0x100]);
            if (i < n-1 && text.charAt(i+1) >= 0x100)
                sb.append(' ');
        }
    } 
    return sb.toString();
}     
如果“字符串”段落中的字符代表标点之一

字符将被翻译回,并在需要时添加空格。

否则,该字符表示单词数组中的索引; 这个词是

如果跟随当前单词,则检索并可选地添加空格

换句话说。 再次比较该方法中的'compress()'方法

上一篇文章的部分:它只是执行反向操作。

简单的文本检索

在深入研究真正的检索之前,这里有一些简单的功能:

库类为此使用了一个非常简单的类,即SectionList类。

这是部分的列表,或者在Java中是:List <String>。 这是这样做的:


class SectionList extends AbstractList<String> { 
    private Section[] section;
    private int lo, n; 
    SectionList(Section[] section, int lo, int n) { 
        this.section= section;
        this.lo        = lo;
        this.n        = n;
    } 
    public String get(int i) { return section[i+lo].getName(); } 
    public int size() { return n; }
} 
构造函数采用一个Sections数组,一个“ lo”索引和

相邻节,这也是列表本身的长度。 清单有

String类型的值; 从各个节中检索字符串

他们自己。 请注意,AbstractList <String>超类负责

使该对象成为完整列表的其余功能。

以下所有方法都利用此小类:


public List<String> getGroups() {  
    return new SectionList(groups, 0, groups.length); 
} 
public List<String> getBooks() {  
    return new SectionList(books, 0, books.length); 
} 
public List<String> getBooks(String group) { 
    int i= getIndex(groups, group); 
    return (i < 0)?null:new SectionList(books, groups[i].getIndex(), groups[i].getTotal());
} 
public List<String> getChapters() {  
    return new SectionList(chapters, 0, chapters.length); 
} 
public List<String> getChapters(String book) { 
    int i= getIndex(books, book); 
    return (i < 0)?null:new SectionList(chapters, books[i].getIndex(), books[i].getTotal());
} 
请注意,大多数方法如何使用上文所述的'getIndex()'方法

为了获得Section数组之一中的索引范围。 字符串列表

照顾其余的。 真的就是这么简单。 最后一个方法返回一个

包含整个文本中所有唯一词但不包含任何唯一词的列表

特定顺序。

下一个小方法返回所有唯一单词的不可修改列表

顺序不限,以防万一您对这样的列表感兴趣:


public List<String> getWords() { 
    return Collections.unmodifiableList(Arrays.asList(words));
} 
鉴于我们的示例库存储了

詹姆士国王圣经的文字:


Library lib= Library.load("/usr/jos/tmp/kj.txtlib"); // get the library 
// show all books:
List<String> books= lib.getBooks();
for (String book : books)
    System.out.println(book); 
// show all chapters in book "Genesis"
List<String> chapters= lib.getChapters("Genesis");
for (String chapter : chapters)
    System.out.println(chapter); 
对于实际的段落文本,我们不能使用此StringList,而只是定义

另一个小类:BookMark类。 我们还需要另一种方法

库类本身:


BookMark getBookMark(int paragraph) { return new BookMarkImpl(paragraph); } 
我们不知道什么是BookMarkImpl类,但是可以肯定它是一个实现

书签界面。 我将在稍后解释此实现。 这是我们的

书签列表:


class BookMarkList extends AbstractList<BookMark> { 
    private Library lib;
    private int lo, n; 
    BookMarkList(Library lib, int lo, int n) { 
        this.lib= lib;
        this.lo    = lo;
        this.n    = n;
    } 
    public BookMark get(int i) { return lib.getBookMark(i+lo); } 
    public int size() { return n; }
} 
请注意,该类对BookMarkImpl类一无所知,即

只对书签(界面)感兴趣。 类似于我们之前的清单

类,它为辛苦的工作实现了AbstractList,并返回一个

为其“ get()”方法添加书签。 我们相信神秘的BookMarkImpl类

实施适当的“ toString()”。

以下是使用这些类的Library类中的方法:


public List<BookMark> getParagraphs() {  
    return new BookMarkList(this, 0, paragraphs.length); 
} 
public List<BookMark> getParagraphs(String book) { 
    int i= getIndex(books, book); 
    if (i < 0) return null; 
    int clo= books[i].getIndex();
    int chi= books[i].getTotal()+clo-1; 
    int p= chapters[clo].getIndex();
    int n= chapters[chi].getIndex()+chapters[chi].getTotal()-p; 
    return new BookMarkList(this, p, n);
} 
public List<BookMark> getParagraphs(String book, String chapter) { 
    int i= getIndex(books, book); 
    if (i < 0) return null; 
    int c= getIndex(chapters, chapter, books[i].getIndex(), books[i].getTotal()); 
    return (c < 0)?null:new BookMarkList(this, chapters[c].getIndex(), chapters[c].getTotal());
} 
再次观察到'getIndex()'方法再次被大量使用。 所有这些

方法要做的是找出段落数组的哪些部分必须包含在其中

List <BookMark>。

一个示例用法可以是:


Library lib= Library.load("/usr/jos/tmp/kj.txtlib"); // get the library 
// show all text for the book Genesis:
List<Bookmark> paragraphs= lib.getParagraphs("Genesis");
for (BookMark paragraph : paragraphs)
    System.out.println(paragraph); 
// show all text in the entire bible"
List<BookMark> paragraphs= lib.getParagraphs();
for (BookMark paragraph: paragraphs)
    System.out.println(paragraph); 
结束语

上述方法使我们可以执行以下所有操作:

  • 产生所有组名的列表
  • 产生所有书籍名称的清单
  • 产生一组书名列表
  • 产生所有章节名称的列表
  • 产生书中章节名称的列表
  • 产生所有段落的列表
  • 生成书中的段落列表
  • 在书的一章中产生段落列表

这很有趣,但是仍然不允许进行高级文本检索。 即

稍微摆弄一下“ grep”,我们可以做的甚至更多。 下一章

引入查询对象,使我们能够真正地挖掘文本并产生

相当先进的结果。

本文部分再次充满了代码,我称之为一天。 我想见你

下次在本文的下一部分中。 我将附上所有的代码

到那时为止,我仍然必须为这两个圣经文本找到一个地方,所以你

可以上传它们,将它们转换为Library对象并进行播放。

现在,我希望您能稍微研究一下代码,如果发现错误或发现错误,请通知我

什么都不懂,或者只是说我是个好人;-)

我希望下周再见,

亲切的问候,

乔斯

From: https://bytes.com/topic/java/insights/739705-text-retrieval-systems-4b-library

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值