Lucene

01.数据的分类

结构化数据:有固定类型或者有固定长度的数据

 例如:数据库中的数据(mysql,oracle), 元数据(就是windows中的数据)

结构化数据搜索方法:

    数据库中数据通过sql语句可以搜索

    元数据(windows中的)通过windows提供的搜索栏进行搜索

非结构化数据:没有固定类型和固定长度的数据

    例如: world文档中的数据邮件中的数据

    非结构化数据搜索方法:

    Word文档使用ctrl+F来搜索

顺序扫描法:

    Ctrl+F中是使用的顺序扫描法,拿到搜索的关键字,去文档中,逐字匹配,直到找到和关键字一致的内容为止.

    优点: 如果文档中存在要找的关键字就一定能找到想要的内容

    缺点: 慢效率低

全文检索算法(倒排索引算法):

    将文件中的内容提取出来, 将文字拆封成一个一个的词(分词), 将这些词组成索引(字典中的目录), 搜索的时候先搜索索引,通过索引找文档,这个过程就叫做全文检索.

    

    分词: 去掉停用词(a, an, the ,嗯 ,呵呵),因为搜索的时候搜索这些词没有意义,将句子拆分成词,去掉标点符号和空格

    优点: 搜索速度快

    缺点: 因为创建的索引需要占用磁盘空间,所以这个算法会使用掉更多的磁盘空间,这是用空间换时间

原理:

 相当于字典,分为目录和正文两部分,查询的时候通过先查目录,然后通过目录上标注的页数去正文页查找需要的内容

02.Lucene

什么是lucene

    Luceneapache旗下的顶级项目,是一个全文检索工具包

    Lucene就是一个可以创建全文检索引擎系统的一堆jar.可以使用它来构建全文检索引擎系统,但是它不能独立运

全文检索引擎系统

 放在tomcat下可以独立运行,对外提供全文检索服务.

03.Lucene应用领域

1. 互联网全文检索引擎(比如百度,  谷歌,  必应)

2. 站内全文检索引擎(淘宝京东搜索功能)

3. 优化数据库查询(因为数据库中使用like关键字是全表扫描也就是顺序扫描算法,查询慢)

Lucene下载

    官方网站:http://lucene.apache.org/ 

    版本:lucene4.10.3

    Jdk要求:1.7以上

    IDE:Eclipse

04.Lucene结构

图片1.png 

索引:

    域名:词  这样的形式,

    它里面有指针执行这个词来源的文档

 

    索引库: 放索引的文件夹(这个文件夹可以自己随意创建,在里面放索引就是索引库)

    Term词元就是一个词lucene中词的最小单位

文档:

    Document对象,一个Document中可以有多个Field域对象,Field域对象中是key   value键值对的形式:有域名和域值,

    一个document就是数据库表中的一条记录一个Filed域对象就是数据库表中的一行一列

    这是一个通用的存储结构.

     

创建索引和所有时所用的分词器必须一致

05.操作_创建索引

图片2.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
  * 采集文件系统中的文档数据,放入Lucene中
  * @throws Exception
  */
@Test
public  void  testIndexCreate() throws  Exception{
     List<Document> docList =  new  ArrayList<Document>();
      
     //指定文件目录
     File dir =  new  File( "D:\\searchsource" );
     //循环文件夹,取出文件
     for (File file:dir.listFiles()) {
     String fileName = file.getName();
     String fileContext = FileUtils.readFileToString(file);
     Long fileSize = FileUtils.sizeOf(file);
     //文件系统中的一个文件就是一个document对象
     Document doc =  new  Document();
     //第一个参数叫做域名,第二个参数叫做域值,第三个参数是否存储,yes/no
     TextField nameField =  new  TextField( "fileName" , fileName,Store.YES);
     TextField contextField =  new  TextField( "fileContext" , fileContext,Store.YES);
     TextField sizeField =  new  TextField( "fileSize" , fileSize.toString(),Store.YES);
     
     //将所有的域都存入文档中
     doc.add(nameField);
     doc.add(sizeField);
     doc.add(contextField);
     
     docList.add(doc);
}
 
//创建分词器,StandardAnalyzer是一个标准分词器,对英文效果好,对中文单字分词
Analyzer analyzer =  new  StandardAnalyzer();
 
//指定索引和文档的目录
//RAMDirectory:内存,FSDirectory:磁盘
Directory directory = FSDirectory.open( new  File( "D:\\luceneTest" ));
//创建写对象的初始化对象
IndexWriterConfig config =  new  IndexWriterConfig(Version.LUCENE_4_10_3,analyzer);
 
//创建索引写对象
IndexWriter indexWriter =  new  IndexWriter(directory, config);
 
for (Document doc:docList) {
     indexWriter.addDocument(doc);
}
//提交
indexWriter.commit();
indexWriter.close();
}
}

06.使用Luke查看创建的索引

图片3.png 

图片4.png

图片5.png

07.操作_搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public  class  IndexSearchTest {
@Test
public  void  testIndexSearch() throws  Exception{
//创建分词器:创建索引和搜索时用的分词器一致
Analyzer analyzer =  new  StandardAnalyzer();
 
//创建查询对象,第一个参数是默认搜索域,第二个参数是分词器
//默认搜索域的作用:如果搜索语法中指定域名从指定域中搜索,如果搜索时只写了查询关键字,则从默认搜索域中搜索
QueryParser queryParser =  new  QueryParser( "fileContext" , analyzer);
//查询语法=域名:搜素的关键字
Query query = queryParser.parse( "fileName:apache" );
 
//指定索引和文档的目录
Directory dir = FSDirectory.open( new  File( "D:\\luceneTest" ));
//创建索引和文档读取对象
IndexReader indexReader = IndexReader.open(dir);
//创建索引搜索对象
IndexSearcher indexSearcher =  new  IndexSearcher(indexReader);
//第一个参数为查询语句对象,第二为显示的条数
TopDocs topDocs = indexSearcher.search(query,  10 );
 
System.out.println( "==count=="  + topDocs.totalHits);
 
//从搜索结果对象中获取结果集
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for (ScoreDoc scoreDoc:scoreDocs) {
//获取docID
int  docID = scoreDoc.doc;
//通过文档ID从硬盘读取出相应的文档
Document document = indexReader.document(docID);
//get域名可以取出值打印
System.out.println( "fileName"  + document.get( "fileName" ));
System.out.println( "fileSize"  + document.get( "fileSize" ));
 
System.out.println( "===============================" );
}
}
}

注意:Query query = queryParser.parse("fileName:apache");这个语法自己写

08.域的详细介绍

    是否分词:

    分词的作用是为了索引

    需要分词文件名称文件内容

    不需要分词不需要索引的域不需要分词,还有就是分词后无意义的域不需要分词

       比如: id, ×××号

     

    是否索引:

    索引的的目的是为了搜索.

    需要搜索的域就一定要创建索引,只有创建了索引才能被搜索出来

    不需要搜索的域可以不创建索引

    需要索引文件名称文件内容, id, ×××号等

    不需要索引比如图片地址不需要创建索引, e:\\xxx.jpg

    因为根据图片地址搜索无意义

     

    是否存储:

    存储的目的是为了显示.

    是否存储看个人需要,存储就是将内容放入Document文档对象中保存出来,会额外占用磁盘空间如果搜索的时候需要马上显示出来可以放入document中也就是要存储,这样查询显示速度快如果不是马上立刻需要显示出来,则不需要存储,因为额外占用磁盘空间不划算.

域的各种类型

Field类

数据类型

Analyzed

是否分析

Indexed

是否索引

Stored

是否存储

说明

StringField(FieldName, FieldValue,Store.YES))

字符串

N

Y

YN

这个Field用来构建一个字符串Field,但是不会进行分析,会将整个串存储在索引中,比如(订单号,姓名等)

是否存储在文档中用Store.YESStore.NO决定

LongField(FieldName, FieldValue,Store.YES)

Long

Y

Y

YN

这个Field用来构建一个Long数字型Field,进行分析和索引,比如(价格)

是否存储在文档中用Store.YESStore.NO决定

StoredField(FieldName, FieldValue) 

重载方法,支持多种类型

N

N

Y

这个Field用来构建不同类型Field

不分析,不索引,但要Field存储在文档中

TextField(FieldName, FieldValue, Store.NO)

TextField(FieldName, reader)

 

字符串

Y

Y

YN

如果是一个Reader, lucene猜测内容比较多,会采用Unstored的策略.

 

注意:lucene底层的算法,钱数是要分词的,因为要根据价钱进行对比

例如: 大于12.5元的小于100元的商品搜索出来

 

09.中文索引

图片6.png 

创建分词器Analyzer analyzer = new IKAnalyzer();

010.操作_索引维护(删除)

@Test

public void testIndexDel() throws Exception{

//创建分词器,StandardAnalyzer标准分词器,标准分词器对英文分词效果很好,对中文是单字分词

Analyzer analyzer = new IKAnalyzer();

//指定索引和文档存储的目录

Directory directory = FSDirectory.open(new File("E:\\dic"));

//创建写对象的初始化对象

IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_3analyzer);

//创建索引和文档写对象

IndexWriter indexWriter = new IndexWriter(directoryconfig);


//删除所有

//indexWriter.deleteAll();


//根据名称进行删除

//Term词元,就是一个词, 第一个参数:域名, 第二个参数:要删除含有此关键词的数据

indexWriter.deleteDocuments(new Term("fileName""apache"));


//提交

indexWriter.commit();

//关闭

indexWriter.close();



011.操作_索引维护(更新)

/**

 * 更新就是按照传入的Term进行搜索,如果找到结果那么删除,将更新的内容重新生成一个Document对象

 * 如果没有搜索到结果,那么将更新的内容直接添加一个新的Document对象

 * @throws Exception

 */

@Test

public void testIndexUpdate() throws Exception{

//创建分词器,StandardAnalyzer标准分词器,标准分词器对英文分词效果很好,对中文是单字分词

Analyzer analyzer = new IKAnalyzer();

//指定索引和文档存储的目录

Directory directory = FSDirectory.open(new File("E:\\dic"));

//创建写对象的初始化对象

IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_3analyzer);

//创建索引和文档写对象

IndexWriter indexWriter = new IndexWriter(directoryconfig);



//根据文件名称进行更新

Term term = new Term("fileName""web");

//更新的对象

Document doc = new Document();

doc.add(new TextField("fileName""xxxxxx", Store.YES));

doc.add(new TextField("fileContext""think in java xxxxxxx", Store.NO));

doc.add(new LongField("fileSize", 100L, Store.YES));


//更新

indexWriter.updateDocument(termdoc);


//提交

indexWriter.commit();

//关闭

indexWriter.close();

}