Я пытаюсь распечатать все термины из документов между двумя docID. Но некоторые термины, которые я проиндексировал, не печатаются.
Извините, потому что некоторые вещи написаны в Испании, потому что это проект для моего испанского университета.
У меня есть этот код:
package simpledemo;
import java.nio.file.Paths;
import java.util.List;
import java.util.ArrayList;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.Terms;
import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.index.Fields;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.similarities.Similarity;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.BytesRef;
//import org.apache.lucene.search.similarities.DefaultSimilarity; // FIXME No se pq no detecta esto si aparece en el API de Lucene
public class TopTermsInDocs {
public static void main(String[] args) {
// TODO Poner bien el paquete al que pertenece cd ordenemos el codigo
String usage = "simpledemo.TopTermsInDocs"
+ "[-index INDEX_PATH] [-docID INT1-INT2] [-top N] [-outfile PATH]\n"
+ "The result will be displayed on screen and in a file to be indicated in"
+ "the -outfile path argument, will show for each document its"
+ "docId and the top n terms with its tf, df and tf x idflog10";
String indexPath = null; // TODO mirar si poner uno por defecto o hacer que falle
String[] range = null;
Integer docIdStart = null;
Integer docIdEnd = null;
Integer topN = null;
String outPath = null;
System.out.println(usage);
for (int i = 0; i < args.length; i++) {
switch(args[i]) {
case "-index":
indexPath = args[++i];
break;
case "-docID":
range = args[++i].split("-");
docIdStart = Integer.parseInt(range[0]);
docIdEnd = Integer.parseInt(range[1]);
break;
case "-top":
topN = Integer.parseInt(args[++i]);
break;
case "-outfile":
outPath = args[++i];
}
}
IndexReader reader = null; //Ls inicializo aqui a null pq sino no los voy a poder usar fuera del try
// FIXME descomentar cd lo reconozca DefaultSimilarity similarity = new DefaultSimilarity();
try {
reader = DirectoryReader.open(FSDirectory.open(Paths.get(indexPath)));
int numDocs = reader.numDocs(); // Numero de documentos total
for(int id = docIdStart; id<docIdEnd; id++) {
System.out.println("Voy a printear el docID: " + id);
Fields fields = reader.getTermVectors(id); //Obtengo todos los terminos del documento
for (String fieldName : fields) {
Terms terms = fields.terms(fieldName);
TermsEnum termsEnum = terms.iterator();
BytesRef term = null;
while((term = termsEnum.next()) != null) {
String termText = term.utf8ToString();
long termFreq = termsEnum.totalTermFreq(); //Frecuencia total del termino
int docFreq = termsEnum.docFreq(); //Frecuencia de documento
int tf = (int) Math.round(termFreq / docFreq); //Frecuencia del termino en el documento
// FIXME descomentar cd lo reconozca double idf = similarity.idf(docFreq, numDocs);
int idf = (int) Math.log(numDocs/(docFreq+1)) + 1;
System.out.println("Campo: " + fieldName + " - Término: " + termText + " - tf: " + tf + " - idf: " + idf);
//TODO primero probar si funciona y si funciona puedo hacer una funcion que devuelva una estructura con todo
}
}
System.out.println("\n\n");
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
Я знаю, что параметры -top и -outfile на данный момент не реализованы. Но для проблемы это не имеет значения.
Когда я выполняю его для одного документа, он показывает:
Campo: LastModifiedTimeLucene - Término: 20230408150702014 - tf: 1 - idf: 2
Campo: contents - Término: david - tf: 1 - idf: 2
Campo: contents - Término: hola2 - tf: 1 - idf: 2
Campo: contents - Término: txt - tf: 1 - idf: 2
Campo: creationTime - Término: 2023-04-08 17:07:02 - tf: 1 - idf: 2
Campo: creationTimeLucene - Término: 20230408150702014 - tf: 1 - idf: 2
Campo: lastAccessTime - Término: 2023-04-09 01:10:26 - tf: 1 - idf: 2
Campo: lastAccessTimeLucene - Término: 20230408231026954 - tf: 1 - idf: 2
Campo: lastModifiedTime - Término: 2023-04-08 17:07:02 - tf: 1 - idf: 2
О создании документов у меня есть эта функция:
void indexDoc(IndexWriter writer, Path file, long lastModified) throws IOException {
System.out.println(file.getFileName().toString());
// TODO Añadir la funcionalidad de onlyLines
if (config.validateFile(file.getFileName().toString()))
{
try (InputStream stream = Files.newInputStream(file)) {
// make a new, empty document
Document doc = new Document();
// Add the path of the file as a field named "path". Use a
// field that is indexed (i.e. searchable), but don't tokenize
// the field into separate words and don't index term frequency
// or positional information:
Field pathField = new StringField("path", file.toString(), Field.Store.YES);
doc.add(pathField);
String contents = obtainContents(stream);
FieldType tmp_field_type = new FieldType();
tmp_field_type.setTokenized(true);
tmp_field_type.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS);
tmp_field_type.setStoreTermVectors(contentsTermVectors);
tmp_field_type.setStoreTermVectorPositions(contentsTermVectors);
tmp_field_type.setStored(contentsStored);
tmp_field_type.freeze();
// Add the contents of the file to a field named "contents". Specify a Reader,
// so that the text of the file is tokenized and indexed, but not stored.
// Note that FileReader expects the file to be in UTF-8 encoding.
// If that's not the case searching for special characters will fail.
Field contentsField = new Field("contents", contents, tmp_field_type);
doc.add(contentsField);
// TODO Extender documentacion
Field hostnameField = new StringField("hostname", InetAddress.getLocalHost().getHostName(), Field.Store.YES);
doc.add(hostnameField);
// TODO Extender documentacion
Field threadField = new StringField("thread", Thread.currentThread().getName(), Field.Store.YES);
doc.add(threadField);
// TODO Extender documentacion
BasicFileAttributes at = Files.readAttributes(file, BasicFileAttributes.class);
String type;
if (at.isDirectory()) type = "isDirectory";
else if (at.isRegularFile()) type = "isRegularFile";
else if (at.isSymbolicLink()) type = "iSSymbolicLink";
else if (at.isOther()) type = "isOther";
else type = "error";
doc.add(new StringField("type", type, Field.Store.YES));
// TODO Extender documentacion
doc.add(new LongPoint("sizeKB", at.size())); // ! CUIDAO
doc.add(new StoredField("sizeKB", at.size()));
// Add the last modified date of the file a field named "modified".
// Use a LongPoint that is indexed (i.e. efficiently filterable with
// PointRangeQuery). This indexes to milli-second resolution, which
// is often too fine. You could instead create a number based on
// year/month/day/hour/minutes/seconds, down the resolution you require.
// For example the long value 2011021714 would mean
// February 17, 2011, 2-3 PM.
doc.add(new LongPoint("modified", lastModified));
doc.add(new StoredField("modified", lastModified));
String dateFormat = "yyyy-MM-dd HH:mm:ss";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
FileTime creationTime = at.creationTime();
String creationTimeFormateado = simpleDateFormat.format(new Date(creationTime.toMillis()));
doc.add(new Field("creationTime", creationTimeFormateado, TYPE_STORED));
FileTime lastAccessTime = at.lastAccessTime();
String lastAccessTimeFormateado = simpleDateFormat.format(new Date(lastAccessTime.toMillis()));
doc.add(new Field("lastAccessTime", lastAccessTimeFormateado, TYPE_STORED));
FileTime lastModifiedTime = at.lastModifiedTime();
String lastTimeModifiedTimeFormateado = simpleDateFormat.format(new Date(lastModifiedTime.toMillis()));
doc.add(new Field("lastModifiedTime", lastTimeModifiedTimeFormateado, TYPE_STORED));
Date creationTimelucene = new Date(creationTime.toMillis());
String s1 = DateTools.dateToString(creationTimelucene, DateTools.Resolution.MILLISECOND);
doc.add(new Field("creationTimeLucene", s1, TYPE_STORED));
Date lastAccessTimelucene = new Date(lastAccessTime.toMillis());
String s2 = DateTools.dateToString(lastAccessTimelucene, DateTools.Resolution.MILLISECOND);
doc.add(new Field("lastAccessTimeLucene", s2, TYPE_STORED));
Date lastModifiedTimelucene = new Date(lastModifiedTime.toMillis());
String s3 = DateTools.dateToString(lastModifiedTimelucene, DateTools.Resolution.MILLISECOND);
doc.add(new Field("LastModifiedTimeLucene", s3, TYPE_STORED));
if (demoEmbeddings != null) {
try (InputStream in = Files.newInputStream(file)) {
float[] vector = demoEmbeddings.computeEmbedding(
new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)));
doc.add(
new KnnVectorField("contents-vector", vector, VectorSimilarityFunction.DOT_PRODUCT));
}
}
if (writer.getConfig().getOpenMode() == OpenMode.CREATE) {
// New index, so we just add the document (no old document can be there):
System.out.println("adding " + file);
writer.addDocument(doc);
} else {
// Existing index (an old copy of this document may have been indexed) so
// we use updateDocument instead to replace the old one matching the exact
// path, if present:
System.out.println("updating " + file);
writer.updateDocument(new Term("path", file.toString()), doc);
}
}
}
else
System.out.println("Este archivo va a ser ignorado");
}```
But I have indexed more fields for the document, like file type. Why are they not shown?
Я ожидаю, что вы будете использовать document.getFields(), если вам нужны поля для определенных документов — и имейте в виду, что поля, установленные в Field.Store.NO
, не хранятся ни в каком конкретном документе, в индексе. Это разница между «полями для документа» (о чем, я думаю, вы просите) и «документами для поля».
Я использую Lucene 9.4.2.
Я отредактировал свой вопрос и добавил код, который я использую для индексации каждого документа.
Вы хотите распечатать определенные данные поля:
"из документов между двумя docID"
Отсутствующий пример, который вы конкретно упомянули, был «типом файла», например:
doc.add(new StringField("type", "isDirectory", Field.Store.YES));
Ожидается, что ваш код сможет получить доступ к этому полю, используя:
Fields fields = reader.getTermVectors(id);
Но поле type
не является вектором термов. Это StringField, а именно:
Поле, которое индексируется, но не токенизируется: все значение String индексируется как один токен.
Вместо этого вы можете получить это поле, используя следующее:
reader.document(id).getFields()
Например (здесь я решил использовать forEach
, но вы также можете использовать свой цикл):
for (int id = 0; id < 1; id++) {
reader.document(id).getFields()
.forEach(field -> System.out.println(field.name()
+ " - " + field.stringValue()));
}
Для моего примера type
приведенный выше код печатает:
type - isDirectory
Спасибо за правки к вашему вопросу. Использовать эти правки сложно, так как они не дают mre — есть отсылки к другим методам, тогда как некоторые жестко запрограммированные данные, вероятно, были бы полезнее — например, как мой пример:
doc.add(new StringField("type", "isDirectory", Field.Store.YES));
Это автономно и не зависит от каких-либо файлов или других методов, не указанных в вашем вопросе.
Если в вашем выводе есть дополнительные отсутствующие поля, вы можете посмотреть, какие это типы полей, и, возможно, предоставить пример жестко закодированных данных.
Возможно, для них даже стоит задать новый, более целенаправленный вопрос.
Какую версию Lucene вы используете? Как вы создали используемые вами документы (чтобы мы могли видеть, какие поля вы определили и как вы их определили).