??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲精品国产suv一区88,亚洲av无码国产精品夜色午夜 ,www.亚洲色图http://m.tkk7.com/Swing/category/26948.html<font size="3"><br><font color="#669933"><em>天行? 君子以自Z?lt;/em></font><br><br></font> zh-cnTue, 03 Aug 2010 22:45:17 GMTTue, 03 Aug 2010 22:45:17 GMT60nativeFont和logicalFont在JDK1.4下的重大效率差异http://m.tkk7.com/Swing/archive/2010/08/02/327745.htmlzhtzhtMon, 02 Aug 2010 13:32:00 GMThttp://m.tkk7.com/Swing/archive/2010/08/02/327745.htmlhttp://m.tkk7.com/Swing/comments/327745.htmlhttp://m.tkk7.com/Swing/archive/2010/08/02/327745.html#Feedback0http://m.tkk7.com/Swing/comments/commentRss/327745.htmlhttp://m.tkk7.com/Swing/services/trackbacks/327745.html

最q遇C个很奇怪的问题Q写了一个界面程序,刚开始没?讄字体Q效率还可以Q但是默认字体看着比较隄Q就改用了一个字体,谁知道在jdk1.4扚w试q程中,效率居然比原来要低非帔R常的多?br /> 后来发现如果是jdk1.5及以上版本两者效率几乎一P见附件截图?br /> 而且Swing效率和增强功能来ԌJDK1.6u10及以上版本有非常大的提高Q?br /> 所以如果条件运行,q是都改成JDK1.6u10及以上版?/font>

试代码如下:


public class FontDemo extends JPanel {

    
public static void main(String[] args) {
        JFrame f 
= new JFrame();
        f.setTitle(
"TWaver中文C֌");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setContentPane(
new FontDemo());
        f.setSize(
800600);
        f.setLocationRelativeTo(
null);
        f.setVisible(
true);
    }


    
private TDataBox box = new TDataBox();
    
private BarChart chart = new BarChart(box);

    
private static final int times = 1000;
    
private static final int style = Font.BOLD;
    
private static final int size = 16;

    
public FontDemo() {
        initBox();
        initChart();
        initGUI();
    }


    
private void initGUI() {
        
this.setLayout(new BorderLayout());

        JScrollPane pane 
= new JScrollPane(chart.getLegendPane());

        
this.add(chart, BorderLayout.CENTER);
        
this.add(pane, BorderLayout.EAST);
    }


    
private void initBox() {
        
final List localFonts = new ArrayList();
        List nativeFonts 
= new ArrayList();

        
// get all available fontFamily names
        Font[] fonts = SunGraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
        
for (int i = 0; i < fonts.length; i++{
            
// separate logical and native font
            if (SunGraphicsEnvironment.isLogicalFont(fonts[i])) {
                localFonts.add(fonts[i]);
            }

            
else {
                nativeFonts.add(fonts[i]);
            }

        }


        System.out.println(
"///////////// localFonts test /////////////");
        
for (int i = 0; i < localFonts.size(); i++{
            Font font 
= (Font) localFonts.get(i);
            
long start = System.currentTimeMillis();
            
for (int k = 0; k < times; k++{
                createFont(font);
            }

            
long spendTime = System.currentTimeMillis() - start;
            Node n 
= new Node();
            n.setName(font.getName());
            n.putChartValue(spendTime);
            n.putChartColor(Color.GREEN);
            box.addElement(n);
            
//            System.out.println(">" + spendTime + "\t" + font.getName());
        }

        System.out.println(
"\n///////////// nativeFonts test /////////////");
        
for (int i = 0; i < nativeFonts.size(); i++{
            Font font 
= (Font) nativeFonts.get(i);
            
long start = System.currentTimeMillis();
            
for (int k = 0; k < times; k++{
                createFont(font);
            }

            
long spendTime = System.currentTimeMillis() - start;
            Node n 
= new Node();
            n.setName(font.getName());
            n.putChartValue(spendTime);
            n.putChartColor(Color.RED);
            box.addElement(n);
            
//            System.out.println(">" + spendTime + "\t" + font.getName());
        }

        System.out.println(
"\n$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
    }


    
private void createFont(Font font) {
        
//     font.deriveFont(style, size);
        new Font(font.getName(), style, size);
    }


    
private void initChart() {
        chart.setLegendLayout(TWaverConst.LEGEND_LAYOUT_VERTICAL);
        chart.setLegendOrientation(TWaverConst.LABEL_ORIENTATION_HORIZONTAL);
        chart.setYScaleTextVisible(
true);
        chart.setShadowOffset(
1);
    }

}



1.4试l果


1.6试l果



原帖地址



zht 2010-08-02 21:32 发表评论
]]>
Java中取JVM中内存的Ҏhttp://m.tkk7.com/Swing/archive/2008/04/18/194026.htmlzhtzhtFri, 18 Apr 2008 06:10:00 GMThttp://m.tkk7.com/Swing/archive/2008/04/18/194026.htmlhttp://m.tkk7.com/Swing/comments/194026.htmlhttp://m.tkk7.com/Swing/archive/2008/04/18/194026.html#Feedback4http://m.tkk7.com/Swing/comments/commentRss/194026.htmlhttp://m.tkk7.com/Swing/services/trackbacks/194026.html  Runtime runtime = Runtime.getRuntime();
  long total = runtime.totalMemory();

  long free = runtime.freeMemory();
  System.out.println(total+"-"+free);


totalMemory()
    /**
     * Returns the total amount of memory in the Java virtual machine.
     * The value returned by this method may vary over time, depending on
     * the host environment.
     * <p>
     * Note that the amount of memory required to hold an object of any
     * given type may be implementation-dependent.
     *
     * @return  the total amount of memory currently available for current
     *          and future objects, measured in bytes.
     */
freeMemory()
    /**
     * Returns the amount of free memory in the Java Virtual Machine.
     * Calling the
     * <code>gc</code> method may result in increasing the value returned
     * by <code>freeMemory.</code>
     *
     * @return  an approximation to the total amount of memory currently
     *          available for future allocated objects, measured in bytes.
     */

通过q个ҎQ可以写一个类gWindowsd理器的面板Q?br />

zht 2008-04-18 14:10 发表评论
]]>
Reflect&Proxyhttp://m.tkk7.com/Swing/archive/2008/04/03/190564.htmlzhtzhtThu, 03 Apr 2008 02:57:00 GMThttp://m.tkk7.com/Swing/archive/2008/04/03/190564.htmlhttp://m.tkk7.com/Swing/comments/190564.htmlhttp://m.tkk7.com/Swing/archive/2008/04/03/190564.html#Feedback0http://m.tkk7.com/Swing/comments/commentRss/190564.htmlhttp://m.tkk7.com/Swing/services/trackbacks/190564.htmlReflect&Proxy

Reflect&Proxy are two functions provided by java,
Following is some example about how to use it.

1.Reflect
By reflect, the Class instance can be created, not using 'new' method
as following:
(1)Creating the class instance:
 Class clazz = Class.forName("twaver.Node");//Node.class;
 Constructor cs = clazz.getConstructor(new Class[] { Object.class });
 Object object = cs.newInstance(new Object[] { "ID-679" });
 @param parameterTypes the parameter array
 new Class[] { Object.class }
 means that the process will use the construcor
 which has one parameter to create the class instance.
 cs.newInstance method will create the class instance with the parameter "new Object[] { "ID-679" }"
(2)Getting the class method:
 Method getIDMethod = clazz.getMethod("getID", new Class[] {});
 Method setNameMethod = clazz.getMethod("setName", new Class[] { String.class });
 @param name the name of the method
 @param parameterTypes the list of parameters
 setNameMethod.invoke(object, new Object[] { "todd.zhang" });
 Invokes the setNameMthod of object instance with the parameter  new Object[] { "todd.zhang" }


 
public class ReflectTest {
    
public static void main(String[] args) throws Exception {
        Node node 
= new Node("ID-679");
        node.setName(
"todd.zhang");
        System.out.println(node.getID());
        System.out.println(node.getName());

        System.out.println(
"-----------------------");

        Class clazz 
= Class.forName("twaver.Node");//Node.class;

        Constructor cs 
= clazz.getConstructor(new Class[] { Object.class });
        Method getIDMethod 
= clazz.getMethod("getID"new Class[] {});
        Method setNameMethod 
= clazz.getMethod("setName"new Class[] { String.class });
        Method getNameMethod 
= clazz.getMethod("getName"new Class[] {});

        Object object 
= cs.newInstance(new Object[] { "ID-679" });
        setNameMethod.invoke(object, 
new Object[] { "todd.zhang" });
        System.out.println(getIDMethod.invoke(object, 
new Object[] {}));
        System.out.println(getNameMethod.invoke(object, 
new Object[] {}));
    }
}


2.Proxy
Proxy is an application of reflect function.
 ClassLoader classLoader = ProxyAnything.class.getClassLoader();
 Class[] interfaces = new Class[] { Interface_A.class, Interface_B.class };
 //the interface array that the proxy will realize
 InvocationHandler handler = new ProxyAnything();
 //the handler of the proxy , each invoked method of Interface_A and Interface_B will be hold up by handler
 //the method invoke will turn to the handler first, and hanlder will deside how to deal with the invoke.
 Proxy proxy = (Proxy) Proxy.newProxyInstance(classLoader, interfaces, handler);
 //it is like the implement of interface ,so it can be transform to interface compulsively.
 proxy instanceof Interface_A will be true
 
 Interface_A a = (Interface_A) proxy;
 Interface_B b = (Interface_B) proxy;
 a.do_A1();
 b.do_B2();

InvocationHandler may proxy sereval class,
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
the proxy can be used to judge which it is.
the proxy just is a  rind, each operation will be deal with hanlder


interface Interface_A {
    
public void do_A1();
    
public void do_A2();
    
public void do_A3();
}

interface Interface_B {
    
public void do_B1();
    
public void do_B2();
    
public void do_B3();
}

public class ProxyAnything implements InvocationHandler {

    
private Interface_A businessA;
    
private Interface_B businessB;

    
public ProxyAnything() {
        
this.businessA = new Interface_A() {
            
public void do_A1() {
                System.out.println(
"doing A1");
            }

            
public void do_A2() {
                System.out.println(
"doing A2");
            }

            
public void do_A3() {
                System.out.println(
"doing A3");
            }
        };
        
this.businessB = new Interface_B() {
            
public void do_B1() {
                System.out.println(
"doing B1");
            }

            
public void do_B2() {
                System.out.println(
"doing B2");
            }

            
public void do_B3() {
                System.out.println(
"doing B3");
            }
        };
    }

    
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
        
if (m.getDeclaringClass() == Interface_A.class) {
            
if (m.getName().equals("do_A3")) {
                System.out.println(
"you can not invoke do_A3");
            } 
else {
                
return m.invoke(this.businessA, args);
            }
        }
        
if (m.getDeclaringClass() == Interface_B.class) {
            System.out.println(m.getName() 
+ " is called.");
            
return m.invoke(this.businessB, args);
        }

        
return null;
    }

    
public static void main(String[] args) throws Exception {
        ClassLoader classLoader 
= ProxyAnything.class.getClassLoader();
        Class[] interfaces 
= new Class[] { Interface_A.class, Interface_B.class };
        InvocationHandler handler 
= new ProxyAnything();
        Proxy proxy 
= (Proxy) Proxy.newProxyInstance(classLoader, interfaces, handler);

        
if (proxy instanceof Interface_A) {
            System.out.println(
"proxy instanceof Interface_A");
        }
        
if (proxy instanceof Interface_B) {
            System.out.println(
"proxy instanceof Interface_B");
        }

        Interface_A a 
= (Interface_A) proxy;
        Interface_B b 
= (Interface_B) proxy;

        a.do_A1();
        a.do_A2();
        a.do_A3();
        b.do_B1();
        b.do_B2();
        b.do_B3();

    }

}


zht 2008-04-03 10:57 发表评论
]]>
Lucene学习http://m.tkk7.com/Swing/archive/2007/10/30/156858.htmlzhtzhtTue, 30 Oct 2007 02:02:00 GMThttp://m.tkk7.com/Swing/archive/2007/10/30/156858.htmlhttp://m.tkk7.com/Swing/comments/156858.htmlhttp://m.tkk7.com/Swing/archive/2007/10/30/156858.html#Feedback1http://m.tkk7.com/Swing/comments/commentRss/156858.htmlhttp://m.tkk7.com/Swing/services/trackbacks/156858.html

(?

本文首先介绍了Lucene的一些基本概念,然后开发了一个应用程序演CZ利用Lucene建立索引q在该烦引上q行搜烦的过E?/span>

Lucene ?/span>

Lucene 是一个基?Java 的全文信息检索工具包Q它不是一个完整的搜烦应用E序Q而是Z的应用程序提供烦引和搜烦功能。Lucene 目前?Apache Jakarta 家族中的一个开源项目。也是目前最为流行的Z Java 开源全文检索工具包?/span>

目前已经有很多应用程序的搜烦功能是基?Lucene 的,比如 Eclipse 的帮助系l的搜烦功能。Lucene 能够为文本类型的数据建立索引Q所以你只要能把你要索引的数据格式{化的文本的,Lucene p对你的文档进行烦引和搜烦。比如你要对一?HTML 文档QPDF 文q行索引的话你就首先需要把 HTML 文?PDF 文转化成文本格式的Q然后将转化后的内容交给 Lucene q行索引Q然后把创徏好的索引文g保存到磁盘或者内存中Q最后根据用戯入的查询条g在烦引文件上q行查询。不指定要烦引的文档的格式也?Lucene 能够几乎适用于所有的搜烦应用E序?/span>

?1 表示了搜索应用程序和 Lucene 之间的关p,也反映了利用 Lucene 构徏搜烦应用E序的流E:


?. 搜烦应用E序?Lucene 之间的关p?/span>
?. 搜烦应用E序?Lucene 之间的关p? src=




索引和搜?/span>

索引是现代搜索引擎的核心Q徏立烦引的q程是把源数据处理成非常方便查询的索引文g的过E。ؓ什么烦引这么重要呢Q试想你现在要在大量的文中搜烦含有某个关键词的文Q那么如果不建立索引的话你就需要把q些文档序的读入内存,然后查这个文章中是不是含有要查找的关键词Q这L话就会耗费非常多的旉Q想x索引擎可是在毫秒U的旉内查扑և要搜索的l果的。这是׃建立了烦引的原因Q你可以把烦引想象成q样一U数据结构,他能够你快速的随机讉K存储在烦引中的关键词Q进而找到该关键词所兌的文。Lucene 采用的是一U称为反向烦引(inverted indexQ的机制。反向烦引就是说我们l护了一个词/短语表,对于q个表中的每个词/短语Q都有一个链表描qC有哪些文包含了q个?短语。这样在用户输入查询条g的时候,p非常快的得到搜烦l果。我们将在本pd文章的第二部分详l介l?Lucene 的烦引机Ӟ׃ Lucene 提供了简单易用的 APIQ所以即使读者刚开始对全文本进行烦引的机制q不太了解,也可以非常容易的使用 Lucene 对你的文实现烦引?/span>

Ҏ档徏立好索引后,可以在q些索引上面q行搜烦了。搜索引擎首先会Ҏ索的关键词进行解析,然后再在建立好的索引上面q行查找Q最l返回和用户输入的关键词相关联的文?/span>





Lucene 软g包分?/span>

Lucene 软g包的发布形式是一?JAR 文gQ下面我们分析一下这?JAR 文g里面的主要的 JAVA 包,使读者对之有个初步的了解?/span>

Package: org.apache.lucene.document

q个包提供了一些ؓ装要烦引的文所需要的c,比如 Document, Field。这P每一个文档最l被装成了一?Document 对象?/span>

Package: org.apache.lucene.analysis

q个包主要功能是Ҏ进行分词,因ؓ文在徏立烦引之前必要q行分词Q所以这个包的作用可以看成是为徏立烦引做准备工作?/span>

Package: org.apache.lucene.index

q个包提供了一些类来协助创建烦引以及对创徏好的索引q行更新。这里面有两个基的类QIndexWriter ?IndexReaderQ其?IndexWriter 是用来创建烦引ƈd文档到烦引中的,IndexReader 是用来删除烦引中的文的?/span>

Package: org.apache.lucene.search

q个包提供了对在建立好的索引上进行搜索所需要的cR比?IndexSearcher ?Hits, IndexSearcher 定义了在指定的烦引上q行搜烦的方法,Hits 用来保存搜烦得到的结果?/span>





一个简单的搜烦应用E序

假设我们的电脑的目录中含有很多文本文,我们需要查扑֓些文档含有某个关键词。ؓ了实现这U功能,我们首先利用 Lucene 对这个目录中的文徏立烦引,然后在徏立好的烦引中搜烦我们所要查扄文。通过q个例子读者会对如何利?Lucene 构徏自己的搜索应用程序有个比较清楚的认识?/span>





建立索引

ZҎ进行烦引,Lucene 提供了五个基的类Q他们分别是 Document, Field, IndexWriter, Analyzer, Directory。下面我们分别介l一下这五个cȝ用途:

Document

Document 是用来描q文档的Q这里的文可以指一?HTML 面Q一电子邮Ӟ或者是一个文本文件。一?Document 对象由多?Field 对象l成的。可以把一?Document 对象惌成数据库中的一个记录,而每?Field 对象是记录的一个字Dc?/span>

Field

Field 对象是用来描qC个文的某个属性的Q比如一电子邮件的标题和内容可以用两个 Field 对象分别描述?/span>

Analyzer

在一个文档被索引之前Q首先需要对文档内容q行分词处理Q这部分工作是?Analyzer 来做的。Analyzer cL一个抽象类Q它有多个实现。针对不同的语言和应用需要选择适合?Analyzer。Analyzer 把分词后的内容交l?IndexWriter 来徏立烦引?/span>

IndexWriter

IndexWriter ?Lucene 用来创徏索引的一个核心的c,他的作用是把一个个?Document 对象加到索引中来?/span>

Directory

q个cM表了 Lucene 的烦引的存储的位|,q是一个抽象类Q它目前有两个实玎ͼW一个是 FSDirectoryQ它表示一个存储在文gpȝ中的索引的位|。第二个?RAMDirectoryQ它表示一个存储在内存当中的烦引的位置?/span>

熟悉了徏立烦引所需要的q些cdQ我们就开始对某个目录下面的文本文件徏立烦引了Q清?l出了对某个目录下的文本文g建立索引的源代码?/span>


清单 1. Ҏ本文件徏立烦?/span>
package TestLucene;
            import java.io.File;
            import java.io.FileReader;
            import java.io.Reader;
            import java.util.Date;
            import org.apache.lucene.analysis.Analyzer;
            import org.apache.lucene.analysis.standard.StandardAnalyzer;
            import org.apache.lucene.document.Document;
            import org.apache.lucene.document.Field;
            import org.apache.lucene.index.IndexWriter;
            /**
            * This class demonstrate the process of creating index with Lucene
            * for text files
            */
            public class TxtFileIndexer {
            public static void main(String[] args) throws Exception{
            //indexDir is the directory that hosts Lucene's index files
            File   indexDir = new File("D:\\luceneIndex");
            //dataDir is the directory that hosts the text files that to be indexed
            File   dataDir  = new File("D:\\luceneData");
            Analyzer luceneAnalyzer = new StandardAnalyzer();
            File[] dataFiles  = dataDir.listFiles();
            IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
            long startTime = new Date().getTime();
            for(int i = 0; i < dataFiles.length; i++){
            if(dataFiles[i].isFile() && dataFiles[i].getName().endsWith(".txt")){
            System.out.println("Indexing file " + dataFiles[i].getCanonicalPath());
            Document document = new Document();
            Reader txtReader = new FileReader(dataFiles[i]);
            document.add(new Field("path", dataFiles[i].getCanonicalPath(),
                              Field.Store.YES, Field.Index.TOKENIZED)); document.add(new Field("contents", txtReader)); indexWriter.addDocument(document); } } indexWriter.optimize(); indexWriter.close(); long endTime = new Date().getTime(); System.out.println("It takes " + (endTime - startTime) + " milliseconds to create index for the files in directory " + dataDir.getPath()); } }

在清?中,我们注意到类 IndexWriter 的构造函数需要三个参敎ͼW一个参数指定了所创徏的烦引要存放的位|,他可以是一?File 对象Q也可以是一?FSDirectory 对象或?RAMDirectory 对象。第二个参数指定?Analyzer cȝ一个实玎ͼ也就是指定这个烦引是用哪个分词器Ҏ挡内容进行分词。第三个参数是一个布型的变量,如果?true 的话׃表创Z个新的烦引,?false 的话׃表在原来索引的基上进行操作。接着E序遍历了目录下面的所有文本文档,qؓ每一个文本文档创Z一?Document 对象。然后把文本文的两个属性:路径和内容加入到了两?Field 对象中,接着在把q两?Field 对象加入?Document 对象中,最后把q个文?IndexWriter cȝ add Ҏ加入到烦引中厅R这h们便完成了烦引的创徏。接下来我们q入在徏立好的烦引上q行搜烦的部分?/span>





搜烦文档

利用Luceneq行搜烦像建立索引一样也是非常方便的。在上面一部分中,我们已经Z个目录下的文本文档徏立好了烦引,现在我们p在这个烦引上q行搜烦以找到包含某个关键词或短语的文。Lucene提供了几个基的类来完成这个过E,它们分别是呢IndexSearcher, Term, Query, TermQuery, Hits. 下面我们分别介绍q几个类的功能?/span>

Query

q是一个抽象类Q他有多个实玎ͼ比如TermQuery, BooleanQuery, PrefixQuery. q个cȝ目的是把用户输入的查询字W串装成Lucene能够识别的Query?/span>

Term

Term是搜索的基本单位Q一个Term对象有两个Stringcd的域l成。生成一个Term对象可以有如下一条语句来完成QTerm term = new Term(“fieldName”,”queryWord”); 其中W一个参C表了要在文的哪一个Field上进行查找,W二个参C表了要查询的关键词?/span>

TermQuery

TermQuery是抽象类Query的一个子c,它同时也是Lucene支持的最为基本的一个查询类。生成一个TermQuery对象由如下语句完成: TermQuery termQuery = new TermQuery(new Term(“fieldName”,”queryWord”)); 它的构造函数只接受一个参敎ͼ那就是一个Term对象?/span>

IndexSearcher

IndexSearcher是用来在建立好的索引上进行搜索的。它只能以只ȝ方式打开一个烦引,所以可以有多个IndexSearcher的实例在一个烦引上q行操作?/span>

Hits

Hits是用来保存搜索的l果的?/span>

介绍完这些搜索所必须的类之后Q我们就开始在之前所建立的烦引上q行搜烦了,清单2l出了完成搜索功能所需要的代码?/span>


清单2 Q在建立好的索引上进行搜?/span>
package TestLucene;
            import java.io.File;
            import org.apache.lucene.document.Document;
            import org.apache.lucene.index.Term;
            import org.apache.lucene.search.Hits;
            import org.apache.lucene.search.IndexSearcher;
            import org.apache.lucene.search.TermQuery;
            import org.apache.lucene.store.FSDirectory;
            /**
            * This class is used to demonstrate the
            * process of searching on an existing
            * Lucene index
            *
            */
            public class TxtFileSearcher {
            public static void main(String[] args) throws Exception{
            String queryStr = "lucene";
            //This is the directory that hosts the Lucene index
            File indexDir = new File("D:\\luceneIndex");
            FSDirectory directory = FSDirectory.getDirectory(indexDir,false);
            IndexSearcher searcher = new IndexSearcher(directory);
            if(!indexDir.exists()){
            System.out.println("The Lucene index is not exist");
            return;
            }
            Term term = new Term("contents",queryStr.toLowerCase());
            TermQuery luceneQuery = new TermQuery(term);
            Hits hits = searcher.search(luceneQuery);
            for(int i = 0; i < hits.length(); i++){
            Document document = hits.doc(i);
            System.out.println("File: " + document.get("path"));
            }
            }
            }
            

在清?中,cIndexSearcher的构造函数接受一个类型ؓDirectory的对象,Directory是一个抽象类Q它目前有两个子c:FSDirctory和RAMDirectory. 我们的程序中传入了一个FSDirctory对象作ؓ其参敎ͼ代表了一个存储在盘上的索引的位|。构造函数执行完成后Q代表了q个IndexSearcher以只ȝ方式打开了一个烦引。然后我们程序构造了一个Term对象Q通过q个Term对象Q我们指定了要在文档的内容中搜烦包含关键?#8221;lucene”的文档。接着利用q个Term对象构造出TermQuery对象q把q个TermQuery对象传入到IndexSearcher的searchҎ中进行查询,q回的结果保存在Hits对象中。最后我们用了一个@环语句把搜烦到的文档的\径都打印了出来。好了,我们的搜索应用程序已l开发完毕,怎么P利用Lucene开发搜索应用程序是不是很简单?/span>





ȝ

本文首先介绍?Lucene 的一些基本概念,然后开发了一个应用程序演CZ利用 Lucene 建立索引q在该烦引上q行搜烦的过E。希望本文能够ؓ学习 Lucene 的读者提供帮助?br />

架构概览

图一昄?Lucene 的烦引机制的架构。Lucene 使用各种解析器对各种不同cd的文进行解析。比如对?HTML 文QHTML 解析器会做一些预处理的工作,比如qo文中的 HTML 标签{等。HTML 解析器的输出的是文本内容Q接着 Lucene 的分词器(Analyzer)从文本内容中提取出烦引项以及相关信息Q比如烦引项的出现频率。接着 Lucene 的分词器把这些信息写到烦引文件中?/p>


图一QLucene 索引机制架构
图一QLucene 索引机制架构




用Lucene索引文档

接下来我一步一步的来演C如何利?Lucene Z的文档创建烦引。只要你能将要烦引的文g转化成文本格式,Lucene pZ的文档徏立烦引。比如,如果你想?HTML 文或?PDF 文建立索引Q那么首先你需要从q些文中提取出文本信息Q然后把文本信息交给 Lucene 建立索引。我们接下来的例子用来演C如何利?Lucene 为后~名ؓ txt 的文件徏立烦引?/p>

1Q?准备文本文g

首先把一些以 txt 为后~名的文本文g攑ֈ一个目录中Q比如在 Windows q_上,你可以放?C:\\files_to_index 下面?/p>

2Q?创徏索引

清单1是ؓ我们所准备的文档创建烦引的代码?/p>


清单1Q用 Lucene 索引你的文档
package lucene.index;
            import java.io.File;
            import java.io.FileReader;
            import java.io.Reader;
            import java.util.Date;
            import org.apache.lucene.analysis.Analyzer;
            import org.apache.lucene.analysis.standard.StandardAnalyzer;
            import org.apache.lucene.document.Document;
            import org.apache.lucene.document.Field;
            import org.apache.lucene.index.IndexWriter;
            /**
            * This class demonstrates the process of creating an index with Lucene
            * for text files in a directory.
            */
            public class TextFileIndexer {
            public static void main(String[] args) throws Exception{
            //fileDir is the directory that contains the text files to be indexed
            File   fileDir  = new File("C:\\files_to_index ");
            //indexDir is the directory that hosts Lucene's index files
            File   indexDir = new File("C:\\luceneIndex");
            Analyzer luceneAnalyzer = new StandardAnalyzer();
            IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
            File[] textFiles  = fileDir.listFiles();
            long startTime = new Date().getTime();
            //Add documents to the index
            for(int i = 0; i < textFiles.length; i++){
            if(textFiles[i].isFile() >> textFiles[i].getName().endsWith(".txt")){
            System.out.println("File " + textFiles[i].getCanonicalPath()
            + " is being indexed");
            Reader textReader = new FileReader(textFiles[i]);
            Document document = new Document();
            document.add(Field.Text("content",textReader));
            document.add(Field.Text("path",textFiles[i].getPath()));
            indexWriter.addDocument(document);
            }
            }
            indexWriter.optimize();
            indexWriter.close();
            long endTime = new Date().getTime();
            System.out.println("It took " + (endTime - startTime)
            + " milliseconds to create an index for the files in the directory "
            + fileDir.getPath());
            }
            }
            

正如清单1所C,你可以利?Lucene 非常方便的ؓ文创徏索引。接下来我们分析一下清?中的比较关键的代码,我们先从下面的一条语句开始看赗?/p>


Analyzer luceneAnalyzer = new StandardAnalyzer();
            

q条语句创徏了类 StandardAnalyzer 的一个实例,q个cL用来从文本中提取出烦引项的。它只是抽象c?Analyzer 的其中一个实现。Analyzer 也有一些其它的子类Q比?SimpleAnalyzer {?/p>

我们接着看另外一条语句:


IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
            

q条语句创徏了类 IndexWriter 的一个实例,该类也是 Lucene 索引机制里面的一个关键类。这个类能创Z个新的烦引或者打开一个已存在的烦引ƈ所引添加文档。我们注意到该类的构造函数接受三个参敎ͼW一个参数指定了存储索引文g的\径。第二个参数指定了在索引q程中用什么样的分词器。最后一个参数是个布变量,如果gؓ真,那么pC创徏一个新的烦引,如果gؓ假,pC打开一个已l存在的索引?/p>

接下来的代码演示了如何添加一个文到索引文g中?/p>


Document document = new Document();
            document.add(Field.Text("content",textReader));
            document.add(Field.Text("path",textFiles[i].getPath()));
            indexWriter.addDocument(document);
            

首先W一行创Zc?Document 的一个实例,它由一个或者多个的?Field)l成。你可以把这个类惌成代表了一个实际的文Q比如一?HTML 面Q一?PDF 文Q或者一个文本文件。而类 Document 中的域一般就是实际文档的一些属性。比如对于一?HTML 面Q它的域可能包括标题Q内容,URL {。我们可以用不同cd?Field 来控制文档的哪些内容应该索引Q哪些内容应该存储。如果想获取更多的关?Lucene 的域的信息,可以参?Lucene 的帮助文档。代码的W二行和W三行ؓ文d了两个域Q每个域包含两个属性,分别是域的名字和域的内容。在我们的例子中两个域的名字分别?content"?path"。分别存储了我们需要烦引的文本文g的内容和路径。最后一行把准备好的文档dC索引当中?/p>

当我们把文档d到烦引中后,不要忘记关闭索引Q这h保证 Lucene 把添加的文写回到硬盘上。下面的一句代码演CZ如何关闭索引?/p>


indexWriter.close();
            

利用清单1中的代码Q你可以成功的文本文添加到索引中去。接下来我们看看对烦引进行的另外一U重要的操作Q从索引中删除文档?/p>





从烦引中删除文档

cIndexReader负责从一个已l存在的索引中删除文档,如清?所C?/p>


清单2Q从索引中删除文?/strong>
File   indexDir = new File("C:\\luceneIndex");
            IndexReader ir = IndexReader.open(indexDir);
            ir.delete(1);
            ir.delete(new Term("path","C:\\file_to_index\lucene.txt"));
            ir.close();
            

在清?中,W二行用静态方?IndexReader.open(indexDir) 初始化了c?IndexReader 的一个实例,q个Ҏ的参数指定了索引的存储\径。类 IndexReader 提供了两U方法去删除一个文档,如程序中的第三行和第四行所C。第三行利用文的编h删除文。每个文都有一个系l自动生成的~号。第四行删除了\径ؓ"C:\\file_to_index\lucene.txt"的文档。你可以通过指定文g路径来方便的删除一个文档。值得注意的是虽然利用上述代码删除文档使得该文不能被索到Q但是ƈ没有物理上删除该文。Lucene 只是通过一个后~名ؓ .delete 的文件来标记哪些文档已经被删除。既然没有物理上删除Q我们可以方便的把这些标Cؓ删除的文恢复过来,如清?3 所C,首先打开一个烦引,然后调用Ҏ ir.undeleteAll() 来完成恢复工作?/p>


清单3Q恢复已删除文
File   indexDir = new File("C:\\luceneIndex");
            IndexReader ir = IndexReader.open(indexDir);
            ir.undeleteAll();
            ir.close();
            

你现在也许想知道如何物理上删除烦引中的文,Ҏ也非常简单。清?4 演示了这个过E?/p>


清单4Q如何物理上删除文
File   indexDir = new File("C:\\luceneIndex");
            Analyzer luceneAnalyzer = new StandardAnalyzer();
            IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,false);
            indexWriter.optimize();
            indexWriter.close();
            

在清?4 中,W三行创Zc?IndexWriter 的一个实例,q且打开了一个已l存在的索引。第 4 行对索引q行清理Q清理过E中把所有标Cؓ删除的文物理删除?/p>

Lucene 没有直接提供ҎҎ进行更斎ͼ如果你需要更C个文档,那么你首先需要把q个文从烦引中删除Q然后把新版本的文档加入到烦引中厅R?/p>





提高索引性能

利用 LuceneQ在创徏索引的工E中你可以充分利用机器的g资源来提高烦引的效率。当你需要烦引大量的文gӞ你会注意到烦引过E的瓉是在往盘上写索引文g的过E中。ؓ了解册个问? Lucene 在内存中持有一块缓冲区。但我们如何控制 Lucene 的缓冲区呢?q运的是QLucene 的类 IndexWriter 提供了三个参数用来调整缓冲区的大以及往盘上写索引文g的频率?/p>

1Q合q因子(mergeFactorQ?/p>

q个参数军_了在 Lucene 的一个烦引块中可以存攑֤文以及把盘上的索引块合q成一个大的烦引块的频率。比如,如果合ƈ因子的值是 10Q那么当内存中的文数达?10 的时候所有的文都必d到磁盘上的一个新的烦引块中。ƈ且,如果盘上的索引块的隔数辑ֈ 10 的话Q这 10 个烦引块会被合ƈ成一个新的烦引块。这个参数的默认值是 10Q如果需要烦引的文数非常多的话q个值将是非怸合适的。对批处理的索引来讲Qؓq个参数赋一个比较大的g得到比较好的索引效果?/p>

2Q最合q文数

q个参数也会影响索引的性能。它军_了内存中的文档数臛_辑ֈ多少才能它们写回磁盘。这个参数的默认值是10Q如果你有够的内存Q那么将q个值尽量设的比较大一些将会显著的提高索引性能?/p>

3Q最大合q文档数

q个参数军_了一个烦引块中的最大的文数。它的默认值是 Integer.MAX_VALUEQ将q个参数讄为比较大的值可以提高烦引效率和索速度Q由于该参数的默认值是整型的最大|所以我们一般不需要改动这个参数?/p>

清单 5 列出了这个三个参数用法,清单 5 和清?1 非常怼Q除了清?5 中会讄刚才提到的三个参数?/p>


清单5Q提高烦引性能
/**
            * This class demonstrates how to improve the indexing performance
            * by adjusting the parameters provided by IndexWriter.
            */
            public class AdvancedTextFileIndexer  {
            public static void main(String[] args) throws Exception{
            //fileDir is the directory that contains the text files to be indexed
            File   fileDir  = new File("C:\\files_to_index");
            //indexDir is the directory that hosts Lucene's index files
            File   indexDir = new File("C:\\luceneIndex");
            Analyzer luceneAnalyzer = new StandardAnalyzer();
            File[] textFiles  = fileDir.listFiles();
            long startTime = new Date().getTime();
            int mergeFactor = 10;
            int minMergeDocs = 10;
            int maxMergeDocs = Integer.MAX_VALUE;
            IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
            indexWriter.mergeFactor = mergeFactor;
            indexWriter.minMergeDocs = minMergeDocs;
            indexWriter.maxMergeDocs = maxMergeDocs;
            //Add documents to the index
            for(int i = 0; i < textFiles.length; i++){
            if(textFiles[i].isFile() >> textFiles[i].getName().endsWith(".txt")){
            Reader textReader = new FileReader(textFiles[i]);
            Document document = new Document();
            document.add(Field.Text("content",textReader));
            document.add(Field.Keyword("path",textFiles[i].getPath()));
            indexWriter.addDocument(document);
            }
            }
            indexWriter.optimize();
            indexWriter.close();
            long endTime = new Date().getTime();
            System.out.println("MergeFactor: " + indexWriter.mergeFactor);
            System.out.println("MinMergeDocs: " + indexWriter.minMergeDocs);
            System.out.println("MaxMergeDocs: " + indexWriter.maxMergeDocs);
            System.out.println("Document number: " + textFiles.length);
            System.out.println("Time consumed: " + (endTime - startTime) + " milliseconds");
            }
            }
            

通过q个例子Q我们注意到在调整缓冲区的大以及写盘的频率上?Lucene l我们提供了非常大的灉|性。现在我们来看一下代码中的关键语句。如下的代码首先创徏了类 IndexWriter 的一个实例,然后对它的三个参数进行赋倹{?/p>


int mergeFactor = 10;
            int minMergeDocs = 10;
            int maxMergeDocs = Integer.MAX_VALUE;
            IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
            indexWriter.mergeFactor = mergeFactor;
            indexWriter.minMergeDocs = minMergeDocs;
            indexWriter.maxMergeDocs = maxMergeDocs;
            

下面我们来看一下这三个参数取不同的值对索引旉的媄响,注意参数值的不同和烦引之间的关系。我们ؓq个实验准备?10000 个测试文。表 1 昄了测试结果?/p>


?Q测试结?/strong>
?Q测试结? src=

通过?1Q你可以清楚地看C个参数对索引旉的媄响。在实践中,你会l常的改变合q因子和最合q文数的值来提高索引性能。只要你有够大的内存,你可以ؓ合ƈ因子和最合q文档数q两个参数赋量大的g提高索引效率Q另外我们一般无需更改最大合q文档数q个参数的|因ؓpȝ已经默认它讄成了最大?/p>





Lucene 索引文gl构分析

在分?Lucene 的烦引文件结构之前,我们先要理解反向索引QInverted indexQ这个概念,反向索引是一U以索引ؓ中心来组l文档的方式Q每个烦引项指向一个文序列,q个序列中的文都包含该索引V相反,在正向烦引中Q文占据了中心的位|,每个文指向了一个它所包含的烦引项的序列。你可以利用反向索引L的找到那些文档包含了特定的烦引项。Lucene正是使用了反向烦引作为其基本的烦引结构?/p>





索引文g的逻辑视图

在Lucene 中有索引块的概念Q每个烦引块包含了一定数目的文。我们能够对单独的烦引块q行索。图 2 昄?Lucene 索引l构的逻辑视图。烦引块的个数由索引的文的L以及每个索引块所能包含的最大文数来决定?/p>


?Q烦引文件的逻辑视图
?Q烦引文件的逻辑视图




Lucene 中的关键索引文g

下面的部分将会分析Lucene中的主要的烦引文Ӟ可能分析有些索引文g的时候没有包含文件的所有的字段Q但不会影响到对索引文g的理解?/p>

1Q烦引块文g

q个文g包含了烦引中的烦引块信息Q这个文件包含了每个索引块的名字以及大小{信息。表 2 昄了这个文件的l构信息?/p>


?Q烦引块文gl构
?Q烦引块文gl构

2Q域信息文g

我们知道Q烦引中的文由一个或者多个域l成Q这个文件包含了每个索引块中的域的信息。表 3 昄了这个文件的l构?/p>


?Q域信息文gl构
?Q域信息文gl构

3Q烦引项信息文g

q是索引文g里面最核心的一个文Ӟ它存储了所有的索引的g及相关信息,q且以烦引项来排序。表 4 昄了这个文件的l构?/p>


?Q烦引项信息文gl构
?Q烦引项信息文gl构

4Q频率文?/p>

q个文g包含了包含烦引项的文档的列表Q以及烦引项在每个文中出现的频率信息。如果Lucene在烦引项信息文g中发现有索引和搜烦词相匚w。那?Lucene ׃在频率文件中找有哪些文g包含了该索引V表5昄了这个文件的一个大致的l构Qƈ没有包含q个文g的所有字Dc?/p>


?Q频率文件的l构
?Q频率文件的l构

5Q位|文?/p>

q个文g包含了烦引项在每个文中出现的位|信息,你可以利用这些信息来参与对烦引结果的排序。表 6 昄了这个文件的l构


?Q位|文件的l构
?Q位|文件的l构

到目前ؓ止我们介l了 Lucene 中的主要的烦引文件结构,希望能对你理?Lucene 的物理的存储l构有所帮助?/p>





ȝ

目前已经有非常多的知名的l织正在使用 LuceneQ比如,Lucene ?Eclipse 的帮助系l,ȝ理工学院?OpenCourseWare 提供了搜索功能。通过阅读q篇文章Q希望你能对 Lucene 的烦引机制有所了解Qƈ且你会发现利?Lucene 创徏索引是非常简单的事情?/p>



参考资?

学习


获得产品和技?/strong>



zht 2007-10-30 10:02 发表评论
]]>
վ֩ģ壺 aëƬþѹۿ| ëƬAV뾫Ʒҹ| vva| ŮaëƬѹۿ| һ߹ۿ| þ޾Ʒ벥| ҹ޾Ʒ| ѻɫƬվ| av| ůůձ| ŷղվ| һѻɫƬ| ޾ƷĻ| һƬaѲſ| ޳AVƬ߹ۿ| AëƬվѿ| ִִӲˬƵ| պŷ| ȾþþƷƵ| AVվ| ޹պa߲| ĻӰ߸| ձϵ1ҳϵ| ˳ߵӰ| þһ߹ۿ2020| | 91Ʒѹۿ| ޹ղ뾫Ʒ| 99߾Ʒȫmy| ޳aƬ߲| йŮ69ٸ| ɫAAVѲ| ɫëƬվ| ɫóվ߹ۿ| Ʒѿþþ| Ʒþþþþ| Ů߾Ʒ| պƷAV| vvvv99պƷ| aëƬƵ| ˾Ʒ|