Lucene学习使用小结(一)
XX是什么?
Apache的一个全文检索引擎工具包,可以用来开发全文检索工具.强大的检索工具solr就是基于此.提到这里.首先需要理解下什么是全文检索?什么是搜索引擎?就专业性而言,百度百科可能已经有答案了.我理解的是:
全文检索,是在全部的数据中查找出需要的信息,而悲催的是需要全文检索的数据基本上都是从海量中查询而来;
搜索引擎:通过指定的算法和策略来在海量数据中查找出价值信息并且展示给用户的系统.
搜索引擎的原理
搜索引擎可以分为两个部分:
一是爬虫部分:从网页中爬取数据,并且循环爬取存入临时库中
二是索引部分,将临时库中的通过一定的策略,算法进行提取文字,分词,排序等存入索引区中,再将结果返回给用户.
在这里只是粗浅的介绍好使用lucene,之前在搜索这个问题上采用的一般是数据库的线性搜索,而lucene采用的是倒排索引方式,在此之前需要介绍下什么是倒排索引技术.
在<算法侦探>这本书中提到侦探得到了一个巫师袍的边角线,向一个博学的巫师来查找这是哪种巫师袍,这一情节中有介绍到倒排索引的方式.在一本很强大的巫师袍记录字典中采用了倒排索引的方式来进行记录
比如:(具体数据不记得,此处为杜撰数据)
特征 巫师袍
尼龙 10岁以下巫师袍 女巫师袍
丝绸 20岁以上巫师袍 女巫师袍 水系
蓝色 男巫师袍
何解呢?就是说尼龙材质出现在10岁以下巫师和女巫师这两类中都有,下面的也是以此类推,当我拿到了蓝色尼龙的材质,那么这很肯定是10岁以下的男巫师的袍子,也就是说我们从需要检索的数据中提取词条,将其设置成索引,通过分词进行匹配从而查找结果.
此处再介绍一个更为官方一点的说法:
第一步:首先对原始数据的某些或者全部字段进行编号,制作成文档列表,号码从0开始递增
第二步:对文档数据进行分词,制作出词条表,每一个词条记录下出现此词条的文档编号.并以词条制作索引
第三部,在输入查询条件的时候查找,从词条索引查询出文档编号,再从文档列表中查找出原始数据.
Lucene快速入门(CURD)
Creat
1,引入依赖:
<dependencies> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-core</artifactId> <version>4.10.2</version> </dependency> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-analyzers-common</artifactId> <version>4.10.2</version> </dependency> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-queryparser</artifactId> <version>4.10.2</version> </dependency> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-highlighter</artifactId> <version>4.10.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency> </dependencies> |
编写创建索引代码
@Test public void test4Creat() throws Exception{ //创建document Document document = new Document(); //添加字段信息 document.add(new StringField("id", "1", Store.YES)); document.add(new TextField("text", "我们呀是共产主义接班人啊...么么哒", Store.YES)); //创建索引写出类 //索引存储位置 Directory directory = null; directory = FSDirectory.open(new File("luceneTest")); IndexWriterConfig conf = null; //添加ik分词器 Analyzer analyzer = null; analyzer = new IKAnalyzer(); conf = new IndexWriterConfig(Version.LATEST, analyzer); //设置索引创建方式,create为清空之前再创建新的 conf.setOpenMode(OpenMode.CREATE); IndexWriter indexWriter = new IndexWriter(directory, conf); //向写出类添加文档 indexWriter.addDocument(document); //提交并且关闭 indexWriter.commit(); indexWriter.close();
} |
测试结果:
luke索引工具查看
图中可见:
么么哒等新词并不能正确分词,并且呀,啊等停止词也被分了,而这并不是我们想要的结果,所以在resource文件中添加
IKAnalyzer.cfg.xml配置文件,名称不能改到
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>IK Analyzer 扩展配置</comment> <!--用户可以在这里配置自己的扩展字典 --> <entry key="ext_dict">ext.dic;</entry> <!--用户可以在这里配置自己的扩展停止词字典 --> <entry key="ext_stopwords">stopword.dic;</entry> </properties> |
创建ext.dic文件添加扩展词典
创建stopword.dic添加停止词典
再次运行结果:
Retrieve
编写测试方法
@Test public void testRetrieve() throws Exception{
//索引读取器 IndexReader indexReader = null; //索引存储目录 Directory directory = FSDirectory.open(new File("luceneTest")); indexReader = DirectoryReader.open(directory); //索引查询器 IndexSearcher indexSearcher = new IndexSearcher(indexReader); //词条 Term term = new Term("text", "共产主义"); //query查询,根据词条完全匹配查询 Query query = new TermQuery(term); //读取索引,拿到前n个文档 int n = 10; TopDocs topDocs = indexSearcher.search(query, n); //共查询了多少文档 System.out.println(topDocs.totalHits+"个文档"); //得分 ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) { //拿到文档编号 int doc = scoreDoc.doc; //拿到文档 Document document = indexReader.document(doc); //读取内容 System.out.println(document.get("id")); System.out.println(document.get("text")); } } |
运行结果如下
1个文档 1 我们呀是共产主义接班人啊...么么哒
|
Update(先删再添加)
编写测试类
@Test public void testUpdate() throws Exception{ //创建索引路径 Directory directory = FSDirectory.open(new File("luceneTest")); Analyzer analyzer = new IKAnalyzer(); //索引写出设置 IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST, analyzer); //索引写出器 IndexWriter indexWriter = new IndexWriter(directory, conf);
//创建document Document document = new Document(); document.add(new StringField("id", "1", Store.YES)); document.add(new TextField("text", "继承革命先辈的光荣传统...么么哒", Store.YES));
//修改 indexWriter.updateDocument(new Term("id","1"), document);
indexWriter.commit(); indexWriter.close(); } |
运行结果
更新操作小结
第一:lucene底层是先删除再添加
第二:lucene更新是按照term匹配来删除,如果term匹配到多个文档,那么匹配到的文档都将删除
第三:最好使用不重复字段进行term匹配,例如id
第四:如果id是数值类型,那么可以手动删除,再添加.如何手动删除,见下.
Delete
@Test public void testUpdate() throws Exception{ //创建索引路径 Directory directory = FSDirectory.open(new File("luceneTest")); Analyzer analyzer = new IKAnalyzer(); //索引写出设置 IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST, analyzer); //索引写出器 IndexWriter indexWriter = new IndexWriter(directory, conf); //先查再删,一般而言删除需要精确匹配,此处采用通配匹配来说明其他查询方式 WildcardQuery query = new WildcardQuery(new Term("text","*共*")); //修改 indexWriter.deleteDocuments(query);
indexWriter.commit(); indexWriter.close(); } |
具体的内容推荐官方API