我正在使用lucene 5.4使用正则表达式从文件中搜索某些文本,但是regexpquery不起作用,尽管使用了shortquery和普通查询,并且能够查找带有搜索字符串的文件,但是当我运行正则表达式查询时,lucenece没有找到任何包含该正则表达式的文件。
索引创建代码:
public IndexWriter generateIndex(String docsPath) throws IOException {
String indexPath = System.getProperty("java.io.tmpdir") +File.separator+"indexDirectory";
if (indexPath == null) {
throw new IOException("System property 'java.io.tmpdir' does not specify a tmp dir");
}
File tmpDir = new File(indexPath);
if (!tmpDir.exists()) {
boolean created = tmpDir.mkdirs();
if (!created) {
throw new IOException("Unable to create tmp dir " + tmpDir);
}
}
boolean create = true;
final Path docDir = Paths.get(docsPath);
if (!Files.isReadable(docDir)) {
System.out.println("Document directory '" + docDir.toAbsolutePath()
+ "' does not exist or is not readable, please check the path");
System.exit(1);
}
Date start = new Date();
try {
System.out.println("Indexing to directory '" + indexPath + "'...");
Directory dir = FSDirectory.open(Paths.get(indexPath));
Analyzer analyzer = new StandardAnalyzer();
IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
if (create) {
iwc.setOpenMode(OpenMode.CREATE);
} else {
iwc.setOpenMode(OpenMode.CREATE_OR_APPEND);
}
IndexWriter writer = new IndexWriter(dir, iwc);
indexDocs(writer, docDir);
setIndexWriter(writer);
Date end = new Date();
System.out.println(end.getTime() - start.getTime() + " total milliseconds");
writer.close();
} catch (IOException e) {
System.out.println(" caught a " + e.getClass() + "\n with message: " + e.getMessage());
}
return getIndexWriter();
}
static void indexDocs(final IndexWriter writer, Path path) throws IOException {
if (Files.isDirectory(path)) {
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
try {
indexDoc(writer, file, attrs.lastModifiedTime().toMillis());
} catch (IOException ignore) {
// don't index files that can't be read.
}
return FileVisitResult.CONTINUE;
}
});
} else {
indexDoc(writer, path, Files.getLastModifiedTime(path).toMillis());
}
}
static void indexDoc(IndexWriter writer, Path file, long lastModified) throws IOException {
try (InputStream stream = Files.newInputStream(file)) {
Document doc = new Document();
Field pathField = new StringField("path", file.toString(), Field.Store.YES);
doc.add(pathField);
doc.add(new LongField("modified", lastModified, Field.Store.NO));
doc.add(new TextField("contents",
new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))));
if (writer.getConfig().getOpenMode() == OpenMode.CREATE) {
System.out.println("adding " + file);
writer.addDocument(doc);
} else {
System.out.println("updating " + file);
writer.updateDocument(new Term("path", file.toString()), doc);
}
}
}
使用正则表达式代码搜索文本:
IndexReader reader = DirectoryReader.open(FSDirectory.open(Paths.get(index)));
IndexSearcher searcher = new IndexSearcher(reader);
Analyzer analyzer = new StandardAnalyzer();
BufferedReader in = null;
Query query = new RegexpQuery(new Term("contents", "program-id\\."));
query = query.rewrite(reader);
System.out.println("Searching for: " + query.toString(field));
searcher.search(query, null, 100);
查询正在运行的解析器代码:
QueryParser parser = new QueryParser(field, analyzer);
Query query = parser.parse("+program-id");
我们将搜索的源代码:
IDENTIFICATION DIVISION.
PROGRAM-ID. ACINSTAL.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
请帮忙。
答案 0 :(得分:0)
如评论中所述,正则表达式查询必须与单个标记匹配。没有任何查询类型允许您使用单个正则表达式跨越多个术语。在我看来,一般应该避免对全文内容进行正则表达式查询(如果该字段是一个简单的标识符,或者某些类似的,这是一个不同的故事)。如果您正在使用它们,则可能表示您未能提供有效的全文搜索。您应该支持在可用时使用更典型的全文搜索工具,例如通配符,模糊,邻近和范围查询,或者调整分析以提供更有用的搜索结果。
但是,如果你坚持下去,有两种方法可以支持这种搜索。
您可以以支持搜索需求的方式将分析更改为令牌化。使用StringField
将创建单个令牌,因此正则表达式查询将按预期更多地工作。当然,这会导致性能不佳,并且对更多标准样式的查询会有更差的支持。如果该字段是某种字符串标识符,则这可能是最佳解决方案。如果它是一个全文字段,您希望获得强大的全文搜索支持,那几乎肯定是一个糟糕的解决方案。
您可以使用对情况更有意义的查询。在您提供的示例中,一个简单的短语查询可以很好地完成工作,就像您自己指出的那样,因此很难说出您需要的内容。通常,对于跨多个术语的复杂正则表达式查询,您必须使用SpanQuery
API支持它,通常使用SpanMultiTermQueryWrapper
合并多个SpanNearQuery
。
另外值得注意的是,SurroundQueryParser可用,它旨在与SpanQuery
api一起使用。它不支持正则表达式,但如果通配符查询与SpanNears结合成短语最终成为您所需要的,那么QueryParser可能是一个方便的工具。