搜索引擎开发笔记二

本文详细介绍了如何使用Lucene为TXT文件建立索引,包括创建IndexProcessor类,利用createIndex方法处理文件并构建Document,以及LoadFileToString方法读取文件内容。建立的索引存储在D:indexr文件夹中,通过对比搜索功能类和直接字符串匹配,展示了索引搜索的高效性。然而,由于分词过程可能导致分词不准确,这可能会造成搜索结果的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       上回书说到已经为txt文件进行了简单的预处理,接下来就要开始建立索引了:)。  

       步骤:1.为要处理的内容建立索引    2.构建查询对象    3.在索引中查找

        首先我们要在firstProject的“firstPoject.lucene.process”包下创建一个IndexProcesser。

        代码如下

package firstProject.lucenedemo.process;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import jeasy.analysis.MMAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;

public class IndexProcesser {
	// 成员变量存储创建的索引文件存放的位置
	private String INDEX_STORE_PATH = "D:\\index";

	// 创建索引
	public void createIndex(String inputDir) {
		try {
			// MMAnalyzer作为分词工具创建一个IndexWriter
			IndexWriter writer = new IndexWriter(INDEX_STORE_PATH,
					new MMAnalyzer(), true);
			File filesDir = new File(inputDir);
			// 取得所有需要建立索引的文件数组
			File[] files = filesDir.listFiles();
			// 遍历数组
			for (int i = 0; i < files.length; i++) {
				// 获取文件名
				String fileName = files[i].getName();
				// 判断文件是否为txt类型的文件
				if (fileName.substring(fileName.lastIndexOf("."))
						.equals(".txt")) {
					// 创建一个新的Document
					Document doc = new Document();
					// 为文件名创建一个Field
					Field field = new Field("filename", files[i].getName(),
							Field.Store.YES, Field.Index.TOKENIZED);
					doc.add(field);
					// 为文件内容创建一个Filed
					field = new Field("content", loadFileToString(files[i]),
							Field.Store.NO, Field.Index.TOKENIZED);
					doc.add(field);
					// 把Document加入IndexWriter
					writer.addDocument(doc);
				}
			}
			// 关闭IndexWriter
			writer.close();

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static void main(String[] args) {
		IndexProcesser processor = new IndexProcesser();
		processor.createIndex("D:\\TDDOWNLOAD\\niceFolder");
	}
	public String loadFileToString(File file) {
		try {
			BufferedReader br = new BufferedReader(new FileReader(file));
			StringBuffer sb = new StringBuffer();
			String line = br.readLine();
			while (line != null) {
				sb.append(line);
				line = br.readLine();
			}
			br.close();
			return sb.toString();
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

}


 

上述代码有两个方法

1.createIndex:该方法接受一个参数inputDir,该参数表示等待被建立索引的文件的存放路径。方法会从该路径中取出所有.txt文件,为每一个文件创建一个Lucene的Document文档,并向每个Document文档内加入了一些文件信息,包括文件名以及文件内容。可能你和我一样,现在对这些Document之类的术语朦胧着,不要紧,慢慢来。

2.LoadFileToString:在将文件内容加入到Document时,调用了类中另一个公有方法loadFileToString。它被用来从一个文件中读出其全部内容,并返回一个String类型的对象。该方法较简单,在BufferReader文件夹中,将每行的内容读取并装入StringBuffer中,最后一行返回。

        createIndex中使用了Lucene的API,将建立的Document对象加入到索引中去,也将文件名和文件内容等信息加入了Lucene的索引。


 

现在在查看D:\indexr文件夹就可以发现所有的文本文件建立了索引文本文件越大,.cfs文件越多  欧了,这样索引就建立成功了

 

接下来我们就要建立一个有搜索功能的类 (右键单击"firstProject.lucenedemo.process"->New->class->命名为Search)

代码如下

package firstProject.lucenedemo.process;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermDocs;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;

public class Search {
	
	private String INDEX_STORE_PATH = "D:\\index";

	public void indexSearch(String searchType, String searchKey) {
		try {
			// 根据索引位置建立IndexSearcher
			IndexSearcher searcher = new IndexSearcher(INDEX_STORE_PATH);
			// 建立搜索单元,searchType代表要搜索的Filed,searchKey代表关键字
			Term t = new Term(searchType, searchKey);
			// 由Term生成一个Query
			Query q = new TermQuery(t);
			// 搜索开始时间
			Date beginTime = new Date();
			// 获取一个<document, frequency>的枚举对象TermDocs
			TermDocs termDocs = searcher.getIndexReader().termDocs(t);
			while (termDocs.next()) {
				// 输出在文档中出现关键词的次数和搜索到关键词的文档
				System.out.println("find "+termDocs.freq()+" matches in "+searcher.getIndexReader().document(termDocs.doc()).getField("filename").stringValue());
			}
			// 搜索完成时间
			Date endTime = new Date();
			// 搜索所耗时间
			long timeOfSearch = endTime.getTime() - beginTime.getTime();
			System.out.println("The time For indexsearch is " + timeOfSearch + " ms");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void StringSearch(String keyword, String searchDir) {
		File filesDir = new File(searchDir);
		// 返回目录文件夹所有文件数组
		File[] files = filesDir.listFiles();
		// HashMap保存文件名和匹配次数对
		Map rs = new HashMap();
		// 记录搜索开始时间
		Date beginTime = new Date();
		// 遍历所有文件
		for (int i = 0; i < files.length; i++) {
			// 初始化匹配次数
			int hits = 0;
			try {
				// 读取文件内容
				BufferedReader br = new BufferedReader(new FileReader(files[i]));
				StringBuffer sb = new StringBuffer();
				String line = br.readLine();
				while (line != null) {
					sb.append(line);
					line = br.readLine();
				}
				br.close();
				// 将StringBuffer转化成String,以便于搜索
				String stringToSearch = sb.toString();
				// 初始化fromIndex
				int fromIndex = -keyword.length();
				// 逐个匹配关键词
				while ((fromIndex = stringToSearch.indexOf(keyword, fromIndex
						+ keyword.length())) != -1) {
					hits++;
				}
				// 将文件名和匹配次数加入HashMap
				rs.put(files[i].getName(), new Integer(hits));
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		// 输出查询结果
		Iterator it = rs.keySet().iterator();
		while (it.hasNext()) {
			String fileName = (String) it.next();
			Integer hits = (Integer) rs.get(fileName);
			System.out.println("find " + hits.intValue() + " matches in "
					+ fileName);
		}
		// 记录结束时间
		Date endTime = new Date();
		// 得到搜索耗费时间
		long timeOfSearch = endTime.getTime() - beginTime.getTime();
		System.out.println("The time For string search is " + timeOfSearch + " ms");
	}

}


 

然后再从"first.lucene.test"中建立一个测试类 (右键单击“first.lucene.test"->New->class->命名为SearchTimeCompareTest)

代码如下

package firstProject.lucenedemo.test;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import firstProject.lucenedemo.process.Search;

public class SearchTimeCompareTest {
	public static void main(String[] args) {
		Search search = new Search();
		// 通过索引搜索关键词
		search.indexSearch("content", "她");
		//插入一个分隔行
		System.out.println();
		// 通过String的API搜索关键词
		search.StringSearch("她", "D:\\TDDOWNLOAD\\niceFolder");
	}

}


 

搜索结果

可以看出用索引来找几乎不用时间,而字符串匹配需要10ms。这只是个很小很小的txt,上兆呢?答案不言而喻。

但可以发现两者结果有差异,因为建立索引时,要先分词后建立索引,而分词过程中对于一些词的处理与我们理解的内容不太一样(语义偏差或二义),因此会出现分词不正确的情况。(摘自《开发自己的搜索引擎》人民邮电出版社)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值