我将文本存储在 fileContent 变量中:
created: 2003-09-22T19:01:14Z
Author: be590_guest
GUERRILLA WAR, COUNTERINSURGENCY, AND STATE
FORMATION IN OTTOMAN YEMEN
如果用空格分隔符将其拆分成单词,并翻译成TextWord类的一个对象,然后尝试显示内容,可以看到:
TextWord[0]: created:
TextWord[1]: 2003-09-22T19:01:14Z
Author:
TextWord[2]: be590_guest
TextWord[3]:
GUERRILLA
TextWord[4]: WAR,
TextWord[5]: COUNTERINSURGENCY,
TextWord[6]: AND
TextWord[7]: STATE
TextWord[8]:
FORMATION
TextWord[9]: IN
TextWord[10]: OTTOMAN
TextWord[11]: YEMEN
在 fileContent 变量上创建索引后:
//Создание индекса по данным из файла
public void createIndex(String content) throws IOException {
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(new StandardAnalyzer());
try (IndexWriter writer = new IndexWriter(this.memoryIndex, indexWriterConfig)) {
Document doc = new Document();
FieldType type = new FieldType();
type.setStoreTermVectors(true);
type.setStoreTermVectorPositions(true);
type.setStoreTermVectorOffsets(true);
type.setStored(true);
type.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS);
Field fieldStore = new Field("tags", content, type); //В поле "tags" записываются данные из переменной content
doc.add(fieldStore);
writer.addDocument(doc);
}
catch(Exception e){
e.printStackTrace();
}
}
为此,我使用新的 StandardAnalyzer()。
创建索引后,我想使用此创建的索引在文本文件内容中找到“状态”一词:
String query_pattern = "state"; //Что хочу найти в тексте
DirectoryReader reader = DirectoryReader.open(this.memoryIndex); //Взять индекс из памяти
IndexSearcher searcher = new IndexSearcher(reader); //Создать поисковик по индексу
//Поиск по одному слову
Query query = new QueryParser("tags", analyzer).parse(query_pattern.toLowerCase()); //Запрос на поиск слова по полю tags
TopDocs results = searcher.search(query, 1); //Результат поиска
for (ScoreDoc scoreDoc : results.scoreDocs) { //Если слово было найдено, то...
Fields termVs = reader.getTermVectors(scoreDoc.doc);
Terms f = termVs.terms("tags");
BytesRef ref = new BytesRef(query_pattern.toLowerCase()); //Шаблон в байтах для проверки
TermsEnum te = f.iterator();
PostingsEnum docsAndPosEnum = null;
if (te.seekExact(ref)) { //Если нашли такое слово из шалона, то...
//Узнать позицию и число повторений этого слова
docsAndPosEnum = te.postings(docsAndPosEnum, PostingsEnum.ALL);
int nextDoc = docsAndPosEnum.nextDoc();
assert nextDoc != DocIdSetIterator.NO_MORE_DOCS;
final int freg = docsAndPosEnum.freq();
final int pos = docsAndPosEnum.nextPosition();
final int o = docsAndPosEnum.startOffset();
System.out.println("Word: " + ref.utf8ToString());
System.out.println("[1] of [" + freg + "] Position: " + pos + ", startOffset: " + o + " length: " + ref.length + " Freg: " + freg);
if (freg > 1) { //Число повторений слова в тексте
int i = 2;
for (int iter = 1; iter <= freg - 1; iter++) {
final int posNext = docsAndPosEnum.nextPosition();
System.out.println("[" + i + "] of [" + freg + "] Possition: " + posNext);
i++;
}
}
}
}
单词被定位并显示其位置:
Word: state
Position: 12
我转到我的 TextWord 并且位置 12 没有这样的词,或者没有这样的位置,然后我显示索引中的所有术语及其位置,按顺序排列它们:
Fields termVs = reader.getTermVectors(scoreDoc.doc);
Terms f = termVs.terms("tags");
TermsEnum te = f.iterator();
PostingsEnum docsAndPosEnum = null;
BytesRef bytesRef;
while ((bytesRef = te.next()) != null) { //Пройтись по всем словам из индекса
docsAndPosEnum = te.postings(docsAndPosEnum, PostingsEnum.ALL);
int nextDoc = docsAndPosEnum.nextDoc();
assert nextDoc != DocIdSetIterator.NO_MORE_DOCS;
final int fr = docsAndPosEnum.freq();
final int pos = docsAndPosEnum.nextPosition();
final int o = docsAndPosEnum.startOffset();
System.out.println("Word: " + bytesRef.utf8ToString());
System.out.println("Position: " + pos + ", startOffset: " + o + " length: " + bytesRef.length + " Freg: " + fr);
sortIndexWord.put(bytesRef.utf8ToString(), pos);
if (fr > 1) {
for (int iter = 1; iter <= fr - 1; iter++) {
int posNext = docsAndPosEnum.nextPosition();
//System.out.println("Possition: " + posNext);
sortIndexWord.put(bytesRef.utf8ToString()+String.valueOf(iter), posNext);
}
}
}
我得到了这个数据:
IndexWord: [0]: created
IndexWord: [1]: 2003
IndexWord: [2]: 09
IndexWord: [3]: 22t19
IndexWord: [4]: 01
IndexWord: [5]: 14z
IndexWord: [6]: author
IndexWord: [7]: be590_guest
IndexWord: [8]: guerrilla
IndexWord: [9]: war
IndexWord: [10]: counterinsurgency
IndexWord: [12]: state
IndexWord: [13]: formation
IndexWord: [15]: ottoman
IndexWord: [16]: yemen
可以看出他从位置 11 中去掉了 And 这个词,State 变成了 12,但是如果我只是尝试显示标记,使用与新的 StandardAnalyzer() 索引相同:
public List<String> analyze(String text, Analyzer analyzer) throws IOException {
List<String> result = new ArrayList<String>();
TokenStream tokenStream = analyzer.tokenStream("tags", text);
CharTermAttribute attr = tokenStream.addAttribute(CharTermAttribute.class);
tokenStream.reset();
while (tokenStream.incrementToken()) {
result.add(attr.toString());
}
return result;
}
List<String> list = analyze(myContent, new StandardAnalyzer());
for(int ik = 0 ; ik <= list.size()-1; ik++){
System.out.println("ListWord["+ik+"]: "+list.get(ik));
}
可以看出:
ListWord[0]: created
ListWord[1]: 2003
ListWord[2]: 09
ListWord[3]: 22t19
ListWord[4]: 01
ListWord[5]: 14z
ListWord[6]: author
ListWord[7]: be590_guest
ListWord[8]: guerrilla
ListWord[9]: war
ListWord[10]: counterinsurgency
ListWord[11]: state
ListWord[12]: formation
ListWord[13]: ottoman
ListWord[14]: yemen
And这个词又被删除了,但同时我还有其他索引,我猜不出他删除了哪些词,哪些没有。
问题是,如何将文本中单词的位置与 IndexWriter 给出的位置相匹配?请告诉我如何,提前谢谢。
lucene 对你的
TextWord
. 而position
这与他无关。这是文本中某个位置的一些抽象标识符(在简单的情况下,我们可以假设这是一个标记号,但这完全取决于分析器,它的设置会改变,这个数字将失去意义)。你不需要它。需要分析过程,以便 lucene 知道如何将文本分解为单词。您提交文本作为输入,并且您正在寻找单词,有时不仅仅是一个单词,而是几个单词。分析器设置什么是分隔符的规则,是否需要用连字符单独和/或一起索引单词等。它与匹配在文本中的位置无关,因为 分析器转换输入文本 - 它可以转换一些单词(例如,更改大小写或替换缩写),可以丢弃一些单词,可以将某些东西粘合在一起,甚至可以从现有单词的片段中插入新单词。您还需要在原始文本中的位置,即 在被分析仪处理之前。
主要问题是
PostingsEnum
您不需要positions
,但是offsets
。startOffset
指向存储字段 valueendOffset
中的开始索引和结束索引,即 在您在索引期间传递并存储在索引中的那个中。值本身可以这样获得:查看此示例https://howtodoinjava.com/lucene/lucene-search-highlight-example/和 -a 的源代码
Highligher
,了解它如何使用offsets
它来获取高亮值。