Lucene In Action ch 1 笔记 -- 基本概念

作者:admin

最近想看看Lucene, 在网上找了一些中文资料看看, 看了一些 但是感觉概念还是不太清楚,有时都被自己搞糊涂了. 没办法就下了一本Lucene In Action 今天看完第一章后 结合以前看的一些中文资料 慢慢的才搞明白了一些基本概念,在此记录下来 以备需者:

在第一章中作者 主要讲了Lucene 是什么 能用来干什么, 以及一个 indexing 和 searching 的例子, 通过例子讲解了一点基本(核心)概念.给读者一个基本的Lucene 概况. 然后又介绍了现在流行的 搜索框架.

我们主要来看看 这个 indexing and searching 例子 然后了解一些基本概念.

package lia.meetlucene;

import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;

import java.io.File;
import java.io.IOException;
import java.io.FileReader;
import java.util.Date;

/**
 * This code was originally written for
 * Erik's Lucene intro java.net article
 */
public class Indexer {

  public static void main(String[] args) throws Exception {
    if (args.length != 2) {
      throw new Exception("Usage: java " + Indexer.class.getName()
        " <index dir> <data dir>");
    }
    File indexDir = new File(args[0]); // 在该目录中创建Lucene Incex
    File dataDir = new File(args[1]); // 该目录中存放备索引的文件

    long start = new Date().getTime();
    int numIndexed = index(indexDir, dataDir);
    long end = new Date().getTime();

    System.out.println("Indexing " + numIndexed + " files took "
      + (end - start) + " milliseconds");
  }

  public static int index(File indexDir, File dataDir)
    throws IOException {

    if (!dataDir.exists() || !dataDir.isDirectory()) {
      throw new IOException(dataDir
        " does not exist or is not a directory");
    }

    IndexWriter writer = new IndexWriter(indexDir,
      new StandardAnalyzer(), true);               //(1)创建 Lucene Index
    writer.setUseCompoundFile(false);

    indexDirectory(writer, dataDir);

    int numIndexed = writer.docCount();
    writer.optimize();
    writer.close();                               // close index
    return numIndexed;
  }

  private static void indexDirectory(IndexWriter writer, File dir)
    throws IOException {

    File[] files = dir.listFiles();

    for (int i = 0; i < files.length; i++) {
      File f = files[i];
      if (f.isDirectory()) {
        indexDirectory(writer, f);  //(2) recurse
      else if (f.getName().endsWith(".txt")) {
        indexFile(writer, f);
      }
    }
  }

  private static void indexFile(IndexWriter writer, File f)
    throws IOException {

    if (f.isHidden() || !f.exists() || !f.canRead()) {
      return;
    }

    System.out.println("Indexing " + f.getCanonicalPath());

    Document doc = new Document();
    doc.add(Field.Text("contents"new FileReader(f)));  // (3) index file content
    doc.add(Field.Keyword("filename", f.getCanonicalPath())); // (4) index file name
    writer.addDocument(doc);                   //(5) add document in Lucene index
  }
}

上面的Indexer 使用了几行 Lucene的API, 来indexing 一个目录下面的文件. 运行时候 需要两个参数 , 一个保存index的目录和要索引的文件目录.

在上面的类中,需要下面的一些Lucene classes 来执行 indexing 处理:

IndexWriter

Directory

Analyzer

Document

Field

IndexWriter 是indexing 处理时用到的中心组件,该类create 新index 并且添加documents 到已经存在的index, BTW,在Lucene中还有别的方法来更新index.

Directory: 用来存放index文件的文件目录,该类是个抽象类,用几个子类可以使用,上面使用了File来代表文件路径,在Lucene中用两个主要的Directory子类,一个FSDirectory,一个 RAMDirectory,前者是把index保存到硬盘中的;后者是保存在内存中的,在内存中处理数度当然就相应的快一些 了但只适合于小文件.

Analyzer: 在文件备索引以前要先通过Analyzer分析,去掉一些对search无用的词语(如英语中 的小词 in at a 等等,在Lucene中被称为stop words 的词),还可以处理大小写的问题(是大小写相关啊 还是不相关),使用Lucene时候 选择Analyzer是关键.

Document: 代表一些Fields的集合.可以想象为一些数据的集合.

Field: 在index中的每一个Document中都包含一些 命名的Fields 用Field来构造, 每一个field都是的搜索是符合要求和不符合要求的index中的一些数据,Lucene提供了四种不同的Field,

1,Keyword  不分析 只索引和保存,象一些特殊信息 不可以分割的 如 电话号码 网站 Email 等.

2,UnIndexed 既不索引也不分析,只是把值保存在index中.该类型适合用来显示搜索结果的field,但是你从来不搜索该显示的数据,如URL

3,UnStored UnIndexed的对立面, 分析和索引但是不保存在index中,适合大型数据 只搜索但是不显示原始数据.

4,Test 分析且索引,如果索引数据是String则也保存在index中, 如果是Reader则不保存.

以上的四种类型,把我搞晕几次了, 看了 Lucene in Action 才发现里面解释的比较清楚, 在此抄录下来:

Keyword—Isn’t analyzed, but is indexed and stored in the index verbatim.

This type is suitable for fields whose original value should be preserved in

its entirety, such as URLs, file system paths, dates, personal names, Social

Security numbers, telephone numbers, and so on. For example, we used

the file system path in Indexer (listing 1.1) as a Keyword field.

UnIndexed—Is neither analyzed nor indexed, but its value is stored in the

index as is. This type is suitable for fields that you need to display with

search results (such as a URL or database primary key), but whose values

you’ll never search directly. Since the original value of a field of this type is

stored in the index, this type isn’t suitable for storing fields with very large

values, if index size is an issue.

UnStored—The opposite of UnIndexed. This field type is analyzed and

indexed but isn’t stored in the index. It’s suitable for indexing a large

amount of text that doesn’t need to be retrieved in its original form, such

as bodies of web pages, or any other type of text document.

Text—Is analyzed, and is indexed. This implies that fields of this type can

be searched against, but be cautious about the field size. If the data

indexed is a String, it’s also stored; but if the data (as in our Indexer example)

is from a Reader, it isn’t stored. This is often a source of confusion, so

take note of this difference when using Field.Text.

 

package lia.meetlucene;

import org.apache.lucene.document.Document;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Hits;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.Directory;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import java.io.File;
import java.util.Date;

/**
 * This code was originally written for
 * Erik's Lucene intro java.net article
 */
public class Searcher {

  public static void main(String[] args) throws Exception {
    if (args.length != 2) {
      throw new Exception("Usage: java " + Searcher.class.getName()
        " <index dir> <query>");
    }

    File indexDir = new File(args[0]);  // index 目录
    String q = args[1];   // query 字符串

    if (!indexDir.exists() || !indexDir.isDirectory()) {
      throw new Exception(indexDir +
        " does not exist or is not a directory.");
    }

    search(indexDir, q);
  }

  public static void search(File indexDir, String q)
    throws Exception {
    Directory fsDir = FSDirectory.getDirectory(indexDir, false);
    IndexSearcher is = new IndexSearcher(fsDir);          //(1) 打开index

    Query query = QueryParser.parse(q, "contents",
      new StandardAnalyzer());                            //(2) 解析query
    long start = new Date().getTime();
    Hits hits = is.search(query);                         //(3) 搜索index
    long end = new Date().getTime();

    System.err.println("Found " + hits.length() +
      " document(s) (in " + (end - start) +
      " milliseconds) that matched query '" +
        q + "':");                                    // 打印search 状态

    for (int i = 0; i < hits.length(); i++) {
      Document doc = hits.doc(i);                     // (4) 打印符合条件的文件名字
      System.out.println(doc.get("filename"));
    }
  }
}

上面就是用来搜索 indexer 索引的文件的searcher, 她也需要两个参数, 一个Indexer 创建的index的目录, 一个用来搜索index的query.

在该类中用到了下面几个Lucene中的类:

IndexSearcher

Term

Query

TermQuery

Hits

IndexSearcher 是用来搜索IndexWriter所索引的index,有一些搜索方法可以使用,其中有一些通用的方法是有其超类Searcher实现的,如Hits search(Query q); 这是最简单的一个方法,需要一个Query参数 返回 Hites 实例,

典型的使用如下:

IndexSearcher is = new IndexSearcher(

FSDirectory.getDirectory("/tmp/index", false));

Query q = new TermQuery(new Term("contents", "lucene"));

Hits hits = is.search(q);

Term : 是搜索的基本单元,和Field类似.

A Term is the basic unit for searching. Similar to the Field object, it consists of a

pair of string elements: the name of the field and the value of that field. Note

that Term objects are also involved in the indexing process. However, they’re created

by Lucene’s internals, so you typically don’t need to think about them while

indexing. During searching, you may construct Term objects and use them

together with TermQuery:

Query q = new TermQuery(new Term("contents", "lucene"));

Hits hits = is.search(q);

This code instructs Lucene to find all documents that contain the word lucene in

a field named contents. Because the TermQuery object is derived from the abstract

parent class Query, you can use the Query type on the left side of the statement.

Query:  在Lucene中有很多 Query的子类, 上面我们用的了TermQuery 在后面的章节中我们会看到更多.

TermQuery: 是Lucene支持的最基本类型之一,也是原始查询类型the primitive query types,她是用特定的值来匹配Document中的fields的.也就是用来查询index的.

Hits:包含了符合Query条件的查询结果.

For performance reasons, Hits instances don’t

load from the index all documents that match a query, but only a small portion

of them at a time.

在第一章中 结合在两个实例, 简单介绍了和他们相关的概念,看后感觉蛮好 虽然看的有点慢. 第二章详细介绍了indexing, 不过那是明天的事情了. 路漫漫其修远兮,吾要继续努力哦! ......... :)



来源:Java爱好者 -- J2EE文章精选
录入:admin
阅读:0
日期:2006-8-30 10:21:50

评论(0篇) 】 【 打印 】 【 字体: