1.1. 创建索引
示例:
1 import org.apache.lucene.analysis.Analyzer; 2 3 import org.apache.lucene.analysis.TokenStream; 4 5 import org.apache.lucene.analysis.core.WhitespaceAnalyzer; 6 7 import org.apache.lucene.analysis.standard.StandardAnalyzer; 8 9 import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; 10 11 import org.apache.lucene.document.Document; 12 13 import org.apache.lucene.document.Field; 14 15 import org.apache.lucene.document.StringField; 16 17 import org.apache.lucene.document.TextField; 18 19 import org.apache.lucene.index.DirectoryReader; 20 21 import org.apache.lucene.index.IndexWriter; 22 23 import org.apache.lucene.index.IndexWriterConfig; 24 25 import org.apache.lucene.index.Term; 26 27 import org.apache.lucene.queryparser.classic.ParseException; 28 29 import org.apache.lucene.queryparser.classic.QueryParser; 30 31 import org.apache.lucene.search.*; 32 33 import org.apache.lucene.store.Directory; 34 35 import org.apache.lucene.store.RAMDirectory; 36 37 import org.apache.lucene.util.BytesRef; 38 39 import org.junit.Assert; 40 41 import org.junit.Before; 42 43 import org.junit.Test; 44 45 import org.wltea.analyzer.lucene.IKAnalyzer; 46 47 48 49 import cn.lmc.myworld.common.lucene.LuceneUtils; 50 51 52 53 import java.io.IOException; 54 55 import java.io.StringReader; 56 57 58 59 public class IndexSearchDemo { 60 61 private Directory directory = new RAMDirectory(); 62 63 private String[] ids = {"1", "2"}; 64 65 private String[] teamname = {"fpx", "ig"}; 66 67 private String[] contents = {"涅槃队,凤凰涅槃,勇夺2019LOLS赛冠军!", "翻山队,登峰造极,翻过那座山夺得了2019LOLS赛冠军!"}; 68 69 private String[] players = {"doinb,tian,lwx,crisp,gimgoong", "rookie,jacklove,ning,baolan,theshy"}; 70 71 private IndexWriterConfig indexWriterConfig = new IndexWriterConfig(new IKAnalyzer()); 72 73 private IndexWriter indexWriter; 74 75 76 77 @Before 78 79 public void createIndex() { 80 81 try { 82 83 indexWriter = new IndexWriter(directory, indexWriterConfig); 84 85 for (int i = 0; i < 2; i++) { 86 87 Document document = new Document(); 88 89 Field idField = new StringField("id", ids[i], Field.Store.YES); 90 91 Field teamnameField = new StringField("teamname", teamname[i], Field.Store.YES); 92 93 Field contentField = new TextField("content", contents[i], Field.Store.YES); 94 95 Field playersField = new StringField("players", players[i], Field.Store.YES); 96 97 document.add(idField); 98 99 document.add(teamnameField); 100 101 document.add(contentField); 102 103 document.add(playersField); 104 105 indexWriter.addDocument(document); 106 107 } 108 109 indexWriter.close(); 110 111 } catch (IOException e) { 112 113 e.printStackTrace(); 114 115 } 116 117 } 118 119 120 121 @Test 122 123 public void testTermQuery() throws IOException { 124 125 Term term = new Term("id", "1"); 126 127 IndexSearcher indexSearcher = getIndexSearcher(); 128 129 TopDocs topDocs = indexSearcher.search(new TermQuery(term), 10); 130 131 // 1)打印总记录数(命中数):类似于百度为您找到相关结果约100,000,000个 132 133 long totalHits = topDocs.totalHits.value; 134 135 System.out.println("查询(命中)总的文档条数:"+totalHits); 136 137 // LOGGER.info("查询(命中)文档最大分数:"+topDocs.getMaxScore()); 138 139 // 2)获取指定的最大条数的、命中的查询结果的文档对象集合 140 141 ScoreDoc[] scoreDocs = topDocs.scoreDocs; 142 143 // 打印具体文档 144 145 for (ScoreDoc scoreDoc : scoreDocs) { 146 147 int doc = scoreDoc.doc; 148 149 Document document = indexSearcher.doc(doc); 150 151 // 打印content字段的值 152 153 System.out.println("id: "+document.get("id")); 154 155 System.out.println("teamname: "+document.get("teamname")); 156 157 System.out.println("content: "+document.get("content")); 158 159 System.out.println("players: "+document.get("players")); 160 161 } 162 163 } 164 165 }
先来一个例子测试一下,我们要关注下面几个主要的类:
- Directory
- IndexWriterConfig
- IndexWriter
- IndexSearcher
- TopDocs
- ScoreDoc
- Document
- Field
1.1.1. Directory
由于Lucene的索引是存储在文件系统上面的,因此要通过Directory这个类来实现索引的存储。经常使用到的是下面两个类:
FSDirectory:在文件系统上存储索引文件
RAMDirectory:在内存中暂存索引文件,适用少量索引,大量索引会出现频繁GC
1.1.2. IndexWriterConfig
该类主要用于配置Lucene的分词器。
1.1.3. IndexWriter
该类为Lucene的操作类,可以对索引进行增,删操作。这里可能就会有人问了,”改”和”查”呢?
注意一下:
IndexWriter是有”改”(更新)操作的,但是实现的原理是先删除,后重新插入。因此更新的时候数据必须齐全,不能够只能更新一个字段的情况,这样有可能会出现将其他字段数据清空的问题。
另外,Lucene的索引统一时间内只能有一个IndexWriter来操作,因此设计工具类的时候,IndexWriter尽量设计为单例模式。
至于”查”操作则由另一个类IndexSearcher来实现。
1.1.4. IndexSearcher
该类就是用来查询索引库的索引的。
1.1.5. TopDocs
该类包含IndexSearcher.search()方法返回的具有较高评分的顶部文档
1.1.6. ScoreDoc
该类提供对TopDocs中每条搜索结果的访问接口
1.1.7. Document
Lucene的文档,也可以看作数据库中的一条记录。
1.1.8. Field
Field属于Document的一部分,可以重复。可以看作数据库中的字段。
1.1.8.1. Field的类型
名称 |
说明 |
IntPoint |
对int型字段索引,只索引不存储 |
FloatPoint |
对float型字段索引,只索引不存储 |
LongPoint |
对long型字段索引,只索引不存储 |
DoublePoint |
对double型字段索引,只索引不存储 |
BinaryDocValuesField |
只存储不共享,例如标题类字段 |
NumericDocValuesField |
存储long型字段,用于评分、排序和值检索,可存储值,但需要添加一个单独的StoredField实例 |
SortedDocValuesField |
索引并存储,用于String类型的Field排序,需要在StringField后添加同名的SortedDocValuesField |
StringField |
只索引但不分词,所有的字符串会作为一个整体进行索引,例如通常用于country或id等 |
TextField |
索引并分词,不包括term vectors |
StoredField |
存储Field的值,可以用 IndexSearcher.doc和IndexReader.document来获取存储的Field和存储的值 |
注意:
由于Lucene是没有时间格式的字段的,因此要存储时间,就要将时间转化成数据用数据格式的NumericDocValuesField(建议)来存储。
1.1.8.2. Field.Store
new StringField("id", ids[i], Field.Store.YES);
看这个,可以看到创建索引的时候,每个Field后面都要加一个Field.Store.YES或者Field.Store.NO这两个又是干嘛的呢?
Field.Store.YES:表示会把这个域中的内容完全存储到文件中
Field.Store.NO:表示把这个域的内容不存储到文件中,但是可以被索引