1. 程式人生 > >Lucene之完整搜尋例項

Lucene之完整搜尋例項

1、建立索引器:

package yushibujue;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import org.apache.lucene.analysis.cjk.CJKAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;

import tool.FileList;
import tool.FileText;

public class LuceneIndexer {
   
	 private JTextField jtfa;
	 private JButton jba;
	 private JTextField jtfb;
	 private JButton jbb;
	 private JButton jbc;
	 private static JTextArea jta;
	 
	 //索引器外觀類
	 private void createAndShowGUI(){
		 //設定跨平臺外觀感覺
		 String lf=UIManager.getCrossPlatformLookAndFeelClassName();
		 
		 //GTK外觀感覺
		 //String lf="com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
		 
		 //Sysetm外觀感覺
		// String lf=UIManager.getSystemLookAndFeelClassName();
		 
		 //windows外觀感覺
		// String lf="com.sun.java.swing.plaf.WindowsLookAndFeel";
		 
		 
		 //Metal外觀感覺
		 //String lf="javax.swing.plaf.metal.MetalLookAndFeel";
		 
		 //common use
		 try{
			 
			 UIManager.setLookAndFeel(lf);
			 
		 }catch(Exception e){
			 JOptionPane.showMessageDialog(null,"無法設定外觀感覺!");
		 }
		 
		 //java  感覺
		 JFrame.setDefaultLookAndFeelDecorated(true);
		 JFrame frame=new JFrame("YUSHIBUJUE");
		 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		 
		 final JFileChooser fc=new JFileChooser();
		 fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		 
		 Container con=frame.getContentPane();
		 con.setLayout(new BorderLayout());
		 
		 JPanel jpup=new JPanel();
		 jpup.setLayout(new GridLayout(3,2));
		 jtfa=new JTextField(30);
		 jba=new JButton("選擇被索引的檔案存放路徑");
		 jba.addActionListener(
		      new ActionListener(){
		    	  public void actionPerformed(ActionEvent e){
		    		  int r=fc.showOpenDialog(null);
		    		  if(r==JFileChooser.APPROVE_OPTION){
		    			  jtfa.setText(fc.getSelectedFile().getPath());
		    			  jbc.setEnabled(true);
		    		  }
		    	  }
		      }
		 );
		 
		 jtfb=new JTextField(30);
		 JButton jbb=new JButton("選擇索引的存放路徑");
		 jbb.addActionListener(
		    new ActionListener(){
		    	public void actionPerformed(ActionEvent e){
		    		int r= fc.showOpenDialog(null);
		    		if(r==JFileChooser.APPROVE_OPTION){
		    			jtfb.setText(fc.getSelectedFile().getPath());
		    			jbc.setEnabled(true);
		    		}
		    	}
		    	
		    }
		 
		 );
		 
		 JLabel jl=new JLabel("");
		 jbc=new JButton("建立索引");
		 jbc.addActionListener( 
		    new ActionListener(){
		    	
		    	public void actionPerformed(ActionEvent e){
		    		try{
		    			LuceneIndeerTool.index(jtfa.getText(),jtfb.getText());
		    			//jbc.setEnabled(false);
		    		}catch(Exception ee){
		    			ee.printStackTrace();
		    			jbc.setEnabled(true);
		    			JOptionPane.showMessageDialog(null, "索引建立失敗!");
		    			System.out.println(ee.getMessage());
		    		}
		    	}
		    }
		 
		 );
		 jpup.add(jtfa);
		 jpup.add(jba);
		 jpup.add(jtfb);
		 jpup.add(jbb);
		 jpup.add(jl);
		 jpup.add(jbc);
		 
		 jta=new JTextArea(10,60);
		 JScrollPane jsp=new JScrollPane(jta);
		 con.add(jpup,BorderLayout.NORTH);
		 con.add(jsp,BorderLayout.CENTER);
		 
		 frame.setSize(200,100);
		 frame.pack();
		 frame.setVisible(true);
		 
	 }
	 
	 public static void main(String[] args) {
		SwingUtilities.invokeLater(
		    new Runnable(){

		    	public void run(){
		    		try{
		    			new LuceneIndexer().createAndShowGUI();
		    		}catch(Exception e){
		    			JOptionPane.showMessageDialog(null, "程式載入失敗!");
		    		}
		    	}
		    }
		
		);
	}
	
	//使用內部類LuceneIndexerTool來實現索引工作,這樣就可以把索引建立的情況反映在文字框裡面了
	 
	 
	 static class LuceneIndeerTool{
		//建立索引,被索引的檔案的路徑,索引的路徑
		 public static void index(String filesPath,String indexPath)throws IOException{
			 
			 //建立索引器,我採用lucene4.7寫法
			 
			   File path=new File(indexPath);
			  SimpleFSDirectory indexDir=new SimpleFSDirectory(path);//讀取被索引的檔案目錄
			  CJKAnalyzer analyzer=new CJKAnalyzer(Version.LUCENE_47);//建立一個二分法分析器
			  IndexWriterConfig conf=new IndexWriterConfig(Version.LUCENE_47, analyzer);
			  IndexWriter writer=new IndexWriter(indexDir,conf);
			 
			 
			/* Directory dir=FSDirectory.open(new File(indexPath));
			 Analyzer analyzer=new StandardAnalyzer();
			 IndexWriterConfig config=new IndexWriterConfig(Version.LUCENE_4_10_2,analyzer);
			 IndexWriter writer=new IndexWriter(dir,config);*/
			 
			 //遞迴遍歷檔案目錄來建立索引
			 String s[]=FileList.getFiles(filesPath);
			 int len=s.length;
			 for(int i=0;i<len;i++){
				 File f=new File(s[i]);
				 String ext=getExt(f);//獲取副檔名
				 if(ext.equalsIgnoreCase("htm")||ext.equalsIgnoreCase("html")){
					 Document doc=new Document();
					 
					 //filename field
					 String filename=f.getName();
					 Field field=new Field("filename",filename,Field.Store.YES,Field.Index.ANALYZED);
					 doc.add(field);
					 
					 //uri field
					 String uri=f.getPath();
					 field=new Field("uri",uri,Field.Store.YES,Field.Index.NO);
					 doc.add(field);
					 
					 //cdate field
					 Date dt=new Date(f.lastModified());
					 SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd E");
					 String cdate=sdf.format(dt);
					 field=new Field("cdate",cdate,Field.Store.YES,Field.Index.NO);
					 doc.add(field);
					 
					 //size field
					 double si=f.length();
					 String size="";
					 
					 if(si>1024){
						 size=String.valueOf(Math.floor(si/1024)+"K");
					 }else{
						 size=String.valueOf(si)+"Bytes";

					 }
					 field=new Field("size",size,Field.Store.YES,Field.Index.NO);
					 doc.add(field);
					 
					 //text field 
					 String text=FileText.getText(f);
					 field=new Field("text",text,Field.Store.YES,Field.Index.ANALYZED);
					 doc.add(field);
					 
					 //digest field 
					 String digest="";
					 if(text.length()>200){
						 digest=text.substring(0, 200);
						 
					 }else{
						 digest=text;
					 }
					 
					 field=new Field("digest",digest,Field.Store.YES,Field.Index.ANALYZED);
				     doc.add(field);
						 
				     
				     //歸入索引
				     writer.addDocument(doc);
				     jta.setText(jta.getText()+"已經歸入索引: " +f+"\n");
				 }
				
			 }
			 //關閉索引器
			 writer.close();
			 JOptionPane.showMessageDialog(null, "索引建立完畢!","提示", JOptionPane.INFORMATION_MESSAGE);
		
		 }
		 
		 public static String getExt(File f){
			 String s=f.getName();
			 try{
				 s=s.substring(s.lastIndexOf(".")+1);
				 
			 }catch(Exception e){
				 s="";
			 }
			 return s;
			 
		 }
		 
		 
		 
	 }
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
}

2、建立搜尋器:
package yushibujue;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;

public class LuceneSearcher {
   private JTextField jtfa;
   private JButton jba;
   private JTextField jtfb;
   private JButton jbb;
   private JButton jbc;
   private static JTextArea jta;
   private JTextField jtfc;
   private JButton jbd;
   private JButton jbe;
   
   private void createAndShowGUI(){
	   
	   //設定跨平臺外觀感覺
		 String lf=UIManager.getCrossPlatformLookAndFeelClassName();
		 
		 //GTK外觀感覺
		 //String lf="com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
		 
		 //Sysetm外觀感覺
		// String lf=UIManager.getSystemLookAndFeelClassName();
		 
		 //windows外觀感覺
		// String lf="com.sun.java.swing.plaf.WindowsLookAndFeel";
		 
		 
		 //Metal外觀感覺
		 //String lf="javax.swing.plaf.metal.MetalLookAndFeel";
		 
		 //common use
		 try{
			 UIManager.setLookAndFeel(lf);
		 }catch(Exception ce){
			 JOptionPane.showMessageDialog(null, "無法設定外觀感覺!");
			 
		 }
		 
		 //java feel
		 //java  感覺
		 JFrame.setDefaultLookAndFeelDecorated(true);
		 JFrame frame=new JFrame("YUSHIBUJUE");
		 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		 
		 final JFileChooser fc=new JFileChooser();
		 fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		 
		 Container con=frame.getContentPane();
		 con.setLayout(new BorderLayout());
		 
		 JPanel jpup=new JPanel();
		 jpup.setLayout(new GridLayout(2,2));
		 jtfa=new JTextField(30);
		 jba=new JButton("選擇索引的存放路徑");
		 jba.addActionListener(
			      new ActionListener(){
			    	  public void actionPerformed(ActionEvent e){
			    		  int r=fc.showOpenDialog(null);
			    		  if(r==JFileChooser.APPROVE_OPTION){
			    			  jtfa.setText(fc.getSelectedFile().getPath());
			    		  }
			    	  }
			      }
			    );
		 jtfb=new JTextField(30);
		 JButton jbb=new JButton("搜尋");
		 jbb.addActionListener(
				    new ActionListener(){
				    	public void actionPerformed(ActionEvent e){
				    		 try{
				    			 String indexPath=jtfa.getText();
				    			 String phrase=jtfb.getText();
				    			 new LuceneSearcherTool().search(phrase,indexPath);
				    		 }catch(Exception ex){
				    			 JOptionPane.showMessageDialog(null, "搜尋失敗","提示",JOptionPane.ERROR_MESSAGE);
				    		 }
				    	}
				    }
				  );
		 jpup.add(jtfa);
		 jpup.add(jba);
		 jpup.add(jtfb);
		 jpup.add(jbb);
		 
		 jta=new JTextArea(10,30);
		 JScrollPane jsp=new JScrollPane(jta);
		 
		 JPanel jpdown=new JPanel();
		 jpdown.setLayout(new FlowLayout());
		 jtfc=new JTextField(35);
		 jbd=new JButton("設定匯出路徑");
		 fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
		 jbd.addActionListener(new ActionListener(){
			 
			 public void actionPerformed(ActionEvent e){
				 int r=fc.showOpenDialog(null);
				 if(r==JFileChooser.APPROVE_OPTION){
					 jtfc.setText(fc.getSelectedFile().getPath());
				 }
			 }
					 
		 });
		 
		 jbe=new JButton("匯出搜尋結果");
		 jbe.addActionListener(
			 new ActionListener(){
				 public void actionPerformed(ActionEvent e){
					 try{
						 File f=new File(jtfc.getText());
						 FileWriter fw=new FileWriter(f);
						 PrintWriter pw=new PrintWriter(fw);
						 pw.write(jta.getText());
						 pw.flush();
						 pw.close();
						 JOptionPane.showMessageDialog(null, "寫入檔案成功!","提示",JOptionPane.INFORMATION_MESSAGE);					 
				       }catch(IOException ioe){
						     JOptionPane.showMessageDialog(null, "寫入檔案失敗!","提示",JOptionPane.ERROR_MESSAGE);
					   }
			    }
			 }
             
         );
		 
		 
		 jpdown.add(jtfc);
		 jpdown.add(jbd);
		 jpdown.add(jbe);
		 
		 con.add(jpup,BorderLayout.NORTH);
		 con.add(jsp,BorderLayout.CENTER);
		 con.add(jpdown,BorderLayout.SOUTH);
		 
		 frame.setSize(200,100);
		 frame.pack();
		 frame.setVisible(true); 
		 
   }
   
   
   public static void main(String[] args){
	   SwingUtilities.invokeLater(new Runnable(){
		   
		   public void run(){
			   
			   new LuceneSearcher().createAndShowGUI();
		   }
		   
	   });
   }
   
   static class LuceneSearcherTool{
	   //執行搜尋--搜尋關鍵詞、索引的路徑
	   public static void search(String phrase,String indexPath)throws IOException{
		   //建立索引器
		   IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(FSDirectory.open(new File(indexPath))));
		   
		   //搜尋text欄位
		   Term t=new Term("text",phrase);
		   
		   //生成Query物件
		   TermQuery query=new TermQuery(t);
		   TopDocs topDocs=searcher.search(query,20);
		   
		   ScoreDoc[] scoreDocs=topDocs.scoreDocs;
		   jta.setText("檢索到的記錄數量:"+topDocs.totalHits+"\n");
		   jta.setText(jta.getText()+"*******************"+"\n\n");
		   System.out.println("查詢結果總數:"+topDocs.totalHits+"最大的評分:"+topDocs.getMaxScore());
		   for(int i=0;i<scoreDocs.length;i++){
			   int doc=scoreDocs[i].doc;
			   Document document = searcher.doc(doc); 
			   if(document==null){
				   continue;
			   }
			   
			   //獲得filename欄位,此處採用了強制轉換(try)
			   Field field=(Field) document.getField("filename");
			   String filename=field.stringValue();
			   
			   //uri欄位
			   field=(Field) document.getField("uri");
			   String uri=field.stringValue();
			   
			   //cdate欄位
			   field=(Field) document.getField("cdate");
			   String cdate =field.stringValue();
			   
			   //digest 欄位
			   field=(Field) document.getField("digest");
			   String digest=field.stringValue();
			   
			   StringBuffer sb=new StringBuffer();
			   sb.append("URI:"+uri+"\n");
			   sb.append("filename:"+filename+"\n");
			   sb.append("cdate:"+cdate+"\n");
			   sb.append("digest:"+digest+"\n");
			   sb.append("-------------------"+"\n");
			   
			   jta.setText(jta.getText()+sb.toString());
			   
			  
			   
			   
			   
			   
			   
			   
			  /* System.out.println("content:"+document.get("content"));
			   System.out.println("id:" + scoreDocs[i].doc + "   scors:" + scoreDocs[i].score+"---index--"+scoreDocs[i].shardIndex);
			   */  
		   }
		   
	   }
   }
  
}

效果圖:

索引器:


搜尋器: