【问题标题】:Lucene Search Returns no results when the file contents are savedLucene Search 保存文件内容时不返回结果
【发布时间】:2013-03-11 08:34:20
【问题描述】:

我正在尝试使用 apache lucene 开发日志查询系统。我开发了一个演示代码来索引两个文件,然后搜索查询字符串。

第一个文件包含数据 麦克莱恩

第二个文件包含数据 平托

下面是我用于索引的代码

 fis = new FileInputStream(file);
  DataInputStream in = new DataInputStream(fis);
  BufferedReader br = new BufferedReader(new InputStreamReader(in));
  String strLine;
  Document doc = new Document();

  Document doc = new Document();
    doc.add(new TextField("contents", new BufferedReader(new InputStreamReader(fis, "UTF-8"))));

    doc.add(new StoredField("filename", file.getCanonicalPath()));

    if (indexWriter.getConfig().getOpenMode() == OpenMode.CREATE) {

       System.out.println("adding " + file);
      indexWriter.addDocument(doc);
   } else {

        System.out.println("updating " + file);
        indexWriter.updateDocument(new Term("path", file.getPath()), doc);
      }  

如果我使用此代码,那么我会得到 proffer 结果。但是在显示中我只能显示文件名,因为我只存储了文件名。

所以我修改了代码并使用此代码存储了文件内容

        FileInputStream fis = null;
        if (file.isHidden() || file.isDirectory() || !file.canRead() || !file.exists()) {
            return;
        }
        if (suffix!=null && !file.getName().endsWith(suffix)) {
            return;
        }
        System.out.println("Indexing file " + file.getCanonicalPath());

        try {
          fis = new FileInputStream(file);
        } catch (FileNotFoundException fnfe) {
          System.out.println("File Not Found"+fnfe);

       }
      DataInputStream in = new DataInputStream(fis);
      BufferedReader br = new BufferedReader(new InputStreamReader(in));
      String strLine;   
      String Data="";
     while ((strLine = br.readLine()) != null) 
         {
            Data=Data+strLine;
         }

        Document doc = new Document();
        doc.add(new TextField("contents", Data, Field.Store.YES));
        doc.add(new StoredField("filename", file.getCanonicalPath()));

        if (indexWriter.getConfig().getOpenMode() == OpenMode.CREATE) {

           System.out.println("adding " + file);
          indexWriter.addDocument(doc);
       } else {

            System.out.println("updating " + file);
            indexWriter.updateDocument(new Term("path", file.getPath()), doc);
          }

根据我的理解,我应该得到结果数为 1。它应该显示包含 maclean 的文件的文件名和内容

但是我得到的结果是

-----------结果----------- ---

0 个匹配的文档 找到 0

我在代码中做错了什么还是对此有合理的解释?为什么第一个代码有效而第二个代码无效?

搜索查询代码

 try
   {
    Directory directory = FSDirectory.open(indexDir);
    IndexReader reader = DirectoryReader.open(directory);
    IndexSearcher searcher = new IndexSearcher(reader);
    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_41);

    QueryParser parser = new QueryParser(Version.LUCENE_41, "contents", analyzer);
    Query query = parser.parse(queryStr);
    System.out.println("Searching for: " + query.toString("contents"));
    TopDocs results = searcher.search(query, maxHits);

    ScoreDoc[] hits = results.scoreDocs;
    int numTotalHits = results.totalHits;

    System.out.println("\n\n\n-----------------------Results--------------------------\n\n\n");
   System.out.println(numTotalHits + " total matching documents");


    for (int i = 0; i < numTotalHits; i++) {
        int docId = hits[i].doc;
        Document d = searcher.doc(docId);

                   System.out.println(i+":File name is: "+d.get("filename"));
                   System.out.println(i+":File content is: "+d.get("contents"));



    }
    System.out.println("Found " + numTotalHits);
   }
   catch(Exception e)
   {
    System.out.println("Exception Was caused in SimpleSearcher");
    e.printStackTrace();

   }

【问题讨论】:

  • 您在搜索之前是否关闭/提交了 IndexWriter?
  • 不,我还没有关闭 IndexWriter
  • 能否也发布您的搜索查询代码?

标签: java jakarta-ee lucene


【解决方案1】:

使用 StoredField 代替 TextField

doc.add(new StoredField("Data",Line));

当您使用文本字段时,字符串会被标记化,因此您将无法搜索相同的内容。存储字段存储整个字符串而不对其进行标记。

【讨论】:

  • 您的回答似乎表明 StoredField 将允许在该字段上进行搜索。 StoredField 没有索引,因此根本无法搜索。如果您想将整个字符串作为单个标记进行索引,您可能需要使用StringField 或类似名称。此外,标记化仅适用于字段的索引方式,而不适用于其存储方式。
【解决方案2】:

我认为您的确切问题是,当您为索引字段创建 BufferedReader 时,您已经读取了整个文件,并且流位于文件的末尾,没有进一步的读取。你应该可以通过调用fis.reset();来解决这个问题

但是,您不应该这样做。不要将相同的数据存储在两个单独的字段中,一个用于索引,一个用于存储。相反,设置相同的字段来存储和索引数据。 TextField has a ctor 允许您存储数据和索引,例如:

doc.add(new TextField("contents", Data, Field.Store.YES));

【讨论】:

  • 对@femtoRgon 流的很好观察。但是(在为索引字段创建BufferedReader 之前读取完整文件)也发生在第一个代码(一个发布在顶部)中,并且正如 Maclean 所说,该代码正在获得正确的结果。还是我错过了什么..
  • @Kshitij 我相信第一个示例是正确索引内容,但不存储它们。如果不存储,则无法检索。
  • @MacleanPinto 在将数据写入索引之前尝试打印数据。您正在构建的数据可能与您想象的不太一样。让我感到震惊的是,使用readLine() 获取的连接行将丢失新行,将单词连接成一个应该分开的标记,并弄乱存储的值。解决这个问题可能就像更改为 Data=Data+"\n"+strLine; Luke 一样简单,这是一个非常方便的调试工具。
  • @femtoRgon 我使用的是 lucene 4.1。卢克不支持 4.1 无论如何我已经让它工作了。我使用文本字段进行索引,就像使用建议的那样。并将字符串存储为存储字段以存储数据。但是我确实同意这个 doc.add(new TextField("contents", Data, Field.Store.YES));应该工作。所以无论如何我都会接受它
【解决方案3】:

我认为您的代码可能存在两个问题。

首先,我注意到您没有使用近实时搜索,也没有在阅读之前提交作者。 Lucene 的 IndexReader 拍摄索引的快照,可以是未使用 NRT 时的提交版本,也可以是使用 NRT 时提交和未提交的版本。这可能是您的 IndexReader 无法看到更改的原因。由于您似乎需要并发读写,我建议您使用 NRT 搜索 (IndexReader reader = DirectoryReader.open(indexWriter);)

第二个问题可能是,正如@femtoRgon 所说,您存储的数据可能不是您所期望的。我注意到,当您附加文件内容进行存储时,您似乎丢失了 EOL 字符。建议你用Luke查你的索引http://www.getopt.org/luke/

【讨论】:

    【解决方案4】:

    这适用于 Lucene 4.5:doc.add(new TextField("Data", Data, Field.Store.YES));

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-20
      • 1970-01-01
      • 2013-09-03
      • 2022-01-20
      • 2011-09-26
      • 1970-01-01
      • 2013-10-22
      • 1970-01-01
      相关资源
      最近更新 更多