一、概述
主要用于打开各种不同的文档。也就是我们需要处理不同格式的文档,比如word、pdf
等,这个软件就是用来处理不同格式的文档。也是需要使用命令
java -jar tika-app-1.13.jar
运行。直接file->open
打开相关的文档,这样它就会解析此文档。
二、入门(工程lucene-tika
)
先编写创建索引的工具类:
IndexUtil.java
public void index(){
try {
File f = new File("E:/myeclipse/Lucene/complexFile/相关问题.docx");
Directory dir = FSDirectory.open(new File("E:/myeclipse/Lucene/index1"));
IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(Version.LUCENE_35, new MMSegAnalyzer()));
Document doc = new Document();
//doc.add(new Field("content", new Tika().parse(f)));
doc.add(new Field("content", new FileReader(f)));
writer.addDocument(doc);
writer.close();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (LockObtainFailedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
这里我们先不使用它tika
,看看索引的情况,
TestIndex.java
@Test
public void testIndex(){
IndexUtil util = new IndexUtil();
util.index();
}
这里我们试验一下对一篇word
文档进行分词。然后我们使用luke
进行查看,发现里面的信息都看不懂,完全不能满足我们的要求。在来看使用tika
的情况。注意:这里我们在添加文档的时候也可以使用tika
的方式,不需要传递FileReader
。
- 第一种方式
IndexUtil.java
public String fileToTxt(File f){
//使用AutoDetectParser可以使Tika根据实际情况自动转换需要使用的parser,不需要再手工指定
Parser parser = new AutoDetectParser();
InputStream is = null;//文件输入流
try {
Metadata metadata = new Metadata();
//改变相关的内容,Tika解析文档时会生成的一组说明数据
metadata.set(Metadata.AUTHOR, "yj");
is = new FileInputStream(f);
//所有解析出来的内容会放到它的子类BodyContentHandler中
ContentHandler handler = new BodyContentHandler();
//用来存储需要填入的参数,最少需要设置tikaParser本身
ParseContext context = new ParseContext();
context.set(Parser.class, parser);//为parser指定对象
parser.parse(is, handler, metadata, context);
//获取metadata的信息
for(String name : metadata.names()){
System.out.println(name + ":" + metadata.get(name));
}
return handler.toString();//解析完之后会将结果存在handler中
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (TikaException e) {
e.printStackTrace();
}finally{
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
说明:在试验之前需要导入相关的依赖包。其中我们实例化AutoDetectParser
类来实例化一个Parser
对象,可以让tika
根据不同的文档类型自动转换需要使用的Parser
,不需要手动指定;而Metadata
表示解析文档后生成的一些说明信息,如作者、日期等内容;ContentHandler
就是用来存放解析文档后的内容的;ParseContext
对象用来将之前的Parser
设置进来。
测试:
@Test
public void testTika01(){
IndexUtil util = new IndexUtil();
System.out.println(util.fileToTxt(new File("E:/myeclipse/Lucene/complexFile/相关问题.docx")));
}
说明:测试之后我们可以使用luke
或者tika
查看相关的内容。
- 第二种方式
IndexUtil.java
public String tikaTool(File f) throws IOException, TikaException{
Tika tika = new Tika();
Metadata metadata = new Metadata();
metadata.set(Metadata.REALIZATION, "相关问题.docx");
//获取metadata的信息
/*for(String name : metadata.names()){
System.out.println(name + ":" + metadata.get(name));
}*/
//当然也是可以将信息存入到metadata中的
String str = tika.parseToString(new FileInputStream(f), metadata);
for(String name : metadata.names()){
System.out.println(name + ":" + metadata.get(name));
}
return tika.parseToString(f);
}
说明:可以看到这种方式相比第一种方式要简单的多,但是注意,默认情况下Metadata
对象中是不会有数据的,这和上面那种方式不一样,当然我们也可以使用parseToString
方法将相关信息设置到Metadata
中。
三、对多个文件进行索引(工程lucene-tika1
)
首先我们建立索引FileIndexUtil.java
:
package cn.itcast.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Random;
import org.apache.commons.io.FilenameUtils;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.NumericField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.util.Version;
import org.apache.tika.Tika;
import org.apache.tika.metadata.Metadata;
import com.chenlb.mmseg4j.analysis.MMSegAnalyzer;
public class FileIndexUtil {
private static Directory directory = null;
static {
try {
directory = FSDirectory.open(new File("E:/myeclipse/Lucene/index1"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static Directory getDirectory() {
return directory;
}
private static Document generatorDoc(File f) throws IOException{
Document doc = new Document();
Metadata metadata = new Metadata();
//通过tika进行存储
doc.add(new Field("content", new Tika().parse(new FileInputStream(f), metadata)));
//存储页数,而像html这类文档是没有页数的,需要判断
int pages = 0;
try{
pages = Integer.parseInt(metadata.get("xmpTPg:NPages"));
}catch(Exception e){
e.printStackTrace();
}
doc.add(new NumericField("page",Field.Store.YES, true).setIntValue(pages));
//存储标题
doc.add(new Field("title", FilenameUtils.getBaseName(f.getName()), Field.Store.YES, Field.Index.ANALYZED));
//存储文件类型
doc.add(new Field("type", FilenameUtils.getExtension(f.getName()), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
doc.add(new Field("filename", f.getName(),Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.add(new Field("path", f.getAbsolutePath(),Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.add(new NumericField("date", Field.Store.YES, true).setLongValue(f.lastModified()));
doc.add(new NumericField("size", Field.Store.YES, true).setIntValue((int) (f.length())));
return doc;
}
// 创建索引
public static void index(boolean hasNew) {
IndexWriter writer = null;
try {
writer = new IndexWriter(directory, new IndexWriterConfig(
Version.LUCENE_35, new MMSegAnalyzer()));
if (hasNew) {
writer.deleteAll();//如果我们要新建索引,那么将之前创建的删除
}
File file = new File("E:/myeclipse/Lucene/complexFile");
Document doc = null;
for (File f : file.listFiles()) {
doc = generatorDoc(f);
writer.addDocument(doc);
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (LockObtainFailedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
说明:这里在创建索引时就不使用FileReader
了,而是使用Tika
对象,我们将输入流传递进去。其他内容和之前一样,只是这里如果我们对一个html
文档进行索引时,这个索引是没有页数的,所以我们需要判断,不然会报异常。使用Tika
对文档进行解析之后我们再使用IndexWriter
进行写入。
测试:
@Test
public void testTika03(){
FileIndexUtil.index(true);
}
说明:在测试的时候,虽然通过了测试,但是却报下面这个异常:
com.drew.lang.BufferBoundsException: Attempt to read from beyond end of underlying data source (requested index: 6, requested count: 2, max index: 5)
不知道是不是这个原因,导致我的索引感觉有问题,最明显的就是没有进行中文分词,虽然我给出的分词器是MMSEG
。最后我将tika
换成1.0版本就好了。而这里之所以没有进行中文分词,是因为MMSEG
的包用的不对,应该使用mmseg4j-all-1.8.5-with-dic.jar
。这样就正确了。我们可以使用luke
进行查看。
我们在编写一个搜索方法:
SearchUtill.java
package cn.itcast.util;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
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;
public class SearchUtill {
public void search01() throws Exception{
IndexSearcher searcher = new IndexSearcher(IndexReader.open(FileIndexUtil.getDirectory()));
TermQuery query = new TermQuery(new Term("content", "网络"));
TopDocs tds = searcher.search(query, 20);
for(ScoreDoc sd : tds.scoreDocs){
Document doc = searcher.doc(sd.doc);
System.out.println(doc.get("title"));
}
searcher.close();
}
}
测试:
@Test
public void testTika04() throws Exception{
SearchUtill util = new SearchUtill();
util.search01();
}
说明:我们可以对相关关键词进行搜索,效率挺高的。
四、高亮显示
未完待续。。。