代码之家  ›  专栏  ›  技术社区  ›  fyjham

在Lucene.NET索引中存储关系数据

  •  6
  • fyjham  · 技术社区  · 15 年前

    我目前正试图在一个大型数据库上实现一个基于Lucene.NET的搜索,但我在搜索本质上是关系数据时遇到了一个障碍。

    在高层次上,我试图搜索的数据是分组的,每个项目属于1到3个组。然后,我需要能够搜索组组合中的所有项目(例如:每个项目同时属于组a和组B)。

    这些分组中的每一个都有我正在搜索的数据中存在的ID和描述,但是这些描述可能是彼此的子字符串(例如:一个组名为“Stuff”,另一个组名为“other Stuff”),我不想匹配具有我正在查找的子字符串的类别。

    我一直在考虑在不进行过滤的情况下将数据拉回来,然后过滤ID,但出于性能原因,我打算对Lucene返回的数据进行分页。我也考虑过把ID分开放在空格里,在字段上做一个文本搜索,但这看起来像是一个彻底的黑客。。。

    有人知道如何最好地处理Lucene.NET中的这种搜索吗?(在有人说我使用了错误的工具之前,我想澄清一下,这只是包括全文搜索在内的一组更大过滤器的子集。如果你仍然认为我使用了错误的工具,尽管我很想知道正确的工具是什么)

    1 回复  |  直到 15 年前
        1
  •  5
  •   HakonB    15 年前

    我在Lucene上也遇到过存储关系数据的问题,但您的问题应该很容易解决。

    我猜您可以标记组字段,这样就可以在字段值中搜索子字符串。只需添加未Kenized的字段,它就会像预期的那样工作。

    internal class Program {
        private static void Main(string[] args) {
            var directory = new RAMDirectory();
            var writer = new IndexWriter(directory, new StandardAnalyzer());
            AddDocument(writer, "group", "stuff", Field.Index.UN_TOKENIZED);
            AddDocument(writer, "group", "other stuff", Field.Index.UN_TOKENIZED);
            writer.Close(true);
    
            var searcher = new IndexSearcher(directory);
            Hits hits = searcher.Search(new TermQuery(new Term("group", "stuff")));
    
            for (int i = 0; i < hits.Length(); i++) {
                Console.WriteLine(hits.Doc(i).GetField("group").StringValue());
            }
        }
    
        private static void AddDocument(IndexWriter writer, string name, string value, Field.Index index) {
            var document = new Document();
            document.Add(new Field(name, value, Field.Store.YES, index));
            writer.AddDocument(document);
        }
    }
    

    该示例向索引中添加了两个未加密的文档,搜索内容并获得一个命中率。如果您更改代码以添加标记化的代码,那么您将有两个点击,如您现在所见。

    另一个示例来说明该行为:

        private static void Main(string[] args) {
            var directory = new RAMDirectory();
            var writer = new IndexWriter(directory, new StandardAnalyzer());
    
            var documentA = new Document();
            documentA.Add(new Field("name", "A", Field.Store.YES, Field.Index.UN_TOKENIZED));
            documentA.Add(new Field("group", "stuff", Field.Store.YES, Field.Index.UN_TOKENIZED));
            documentA.Add(new Field("group", "other stuff", Field.Store.YES, Field.Index.UN_TOKENIZED));
            writer.AddDocument(documentA);
            var documentB = new Document();
            documentB.Add(new Field("name", "B", Field.Store.YES, Field.Index.UN_TOKENIZED));
            documentB.Add(new Field("group", "stuff", Field.Store.YES, Field.Index.UN_TOKENIZED));
            writer.AddDocument(documentB);
            var documentC = new Document();
            documentC.Add(new Field("name", "C", Field.Store.YES, Field.Index.UN_TOKENIZED));
            documentC.Add(new Field("group", "other stuff", Field.Store.YES, Field.Index.UN_TOKENIZED));
            writer.AddDocument(documentC);
    
            writer.Close(true);
    
            var query1 = new TermQuery(new Term("group", "stuff"));
            SearchAndDisplay("First sample", directory, query1);
    
            var query2 = new TermQuery(new Term("group", "other stuff"));
            SearchAndDisplay("Second sample", directory, query2);
    
            var query3 = new BooleanQuery();
            query3.Add(new TermQuery(new Term("group", "stuff")), BooleanClause.Occur.MUST);
            query3.Add(new TermQuery(new Term("group", "other stuff")), BooleanClause.Occur.MUST);
            SearchAndDisplay("Third sample", directory, query3);
        }
    
        private static void SearchAndDisplay(string title, Directory directory, Query query3) {
            var searcher = new IndexSearcher(directory);
            Hits hits = searcher.Search(query3);
            Console.WriteLine(title);
            for (int i = 0; i < hits.Length(); i++) {
                Console.WriteLine(hits.Doc(i).GetField("name").StringValue());
            }
        }