C# Lucene.Net(3.0.3或4.8.0)QueryParser可以搜索数字吗?

C# Lucene.Net(3.0.3或4.8.0)QueryParser可以搜索数字吗?,c#,lucene,numbers,lucene.net,query-parser,C#,Lucene,Numbers,Lucene.net,Query Parser,我从Lucene.NET4.8演示项目()开始。我的目标是能够使用查询解析器(QueryParser或MultiFieldQueryParser)搜索文本和数字。可能吗?我所找到的只是使用范围(numeriRangeQuery)的示例,或者是构建我自己的查询解析器的建议。我无法确定是否可以通过现有的查询解析器创建范围 using System; using Lucene.Net.Store; using Lucene.Net.Documents; using Lucene.Net.Index;

我从Lucene.NET4.8演示项目()开始。我的目标是能够使用查询解析器(QueryParser或MultiFieldQueryParser)搜索文本和数字。可能吗?我所找到的只是使用范围(numeriRangeQuery)的示例,或者是构建我自己的查询解析器的建议。我无法确定是否可以通过现有的查询解析器创建范围

using System;
using Lucene.Net.Store;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Util;
using Lucene.Net.QueryParsers.Classic;
using Lucene.Net.Search;
using Lucene.Net.Analysis.Standard;

/*
Package Manager:
Install-Package Lucene.Net -Version 4.8.0-beta00004 -Pre
Install-Package Lucene.Net.Analysis.Common -Version 4.8.0-beta00004 -Pre
Install-Package Lucene.Net.QueryParser -Version 4.8.0-beta00004 -Pre
*/

namespace LuceneNetNumbers
{
    class Program
    {
        static void Main(string[] args)
        {
            LuceneVersion MatchVersion = LuceneVersion.LUCENE_48;

            using (var oDirectory = new RAMDirectory())
            {
                var oAnalyzer = new StandardAnalyzer(MatchVersion);
                var oQueryParser = new MultiFieldQueryParser(MatchVersion, new[] { "name", "height", "age" }, oAnalyzer);
                var oIndexWriterConfig = new IndexWriterConfig(MatchVersion, oAnalyzer);
                var oIndexWriter = new IndexWriter(oDirectory, oIndexWriterConfig);
                var oSearcherManager = new SearcherManager(oIndexWriter, true, null);

                var oAdd = new Action<string, double, int>((sName, nAge, nHeight) =>
                {
                    var oDocument = new Document
                    {
                        new TextField("name", sName, Field.Store.YES),
                        new Int32Field("height", nHeight, Field.Store.YES),
                        new DoubleField("age", nAge, Field.Store.YES),
                    };

                    oIndexWriter.UpdateDocument(new Term("name", sName), oDocument);
                });

                oAdd("John Doe", 24.45, 56);
                oAdd("John Smith", 44.44, 64);
                oAdd("Mike Smith", 56.65, 70);

                oIndexWriter.Flush(true, true);
                oIndexWriter.Commit();

                //

                var oSearch = new Action<string>((sQueryString) =>
                {
                    var oQuery = oQueryParser.Parse(sQueryString);
                    oSearcherManager.MaybeRefreshBlocking();
                    var oSearcher = oSearcherManager.Acquire();

                    try
                    {
                        var oTopDocs = oSearcher.Search(oQuery, 10);
                        var nTotalHits = oTopDocs.TotalHits;
                        Console.WriteLine("Total Hits: {0}", nTotalHits);

                        foreach (var oResult in oTopDocs.ScoreDocs)
                        {
                            var oDocument = oSearcher.Doc(oResult.Doc);

                            var nScore = oResult.Score;
                            var sName = oDocument.GetField("name")?.GetStringValue();
                            var nAge = oDocument.GetField("age")?.GetNumericValue();
                            var nHeight = oDocument.GetField("height")?.GetNumericValue();

                            Console.WriteLine("{0:0.00}, {1,15}, {2,8}, {3,8}", nScore, sName, nAge, nHeight);
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.ToString());
                    }
                    finally
                    {
                        oSearcherManager.Release(oSearcher);
                        oSearcher = null;
                    }
                });

                oSearch("john");
                oSearch("height:64");

                /*
                Output:
                Total Hits: 2
                0.20,        John Doe,    24.45,       56
                0.20,      John Smith,    44.44,       64
                Total Hits: 0
                */
            }
        }
    }
}
使用系统;
使用Lucene.Net.Store;
使用Lucene.Net.Documents;
使用Lucene.Net.Index;
使用Lucene.Net.Util;
使用Lucene.Net.QueryParsers.Classic;
使用Lucene.Net.Search;
使用Lucene.Net.Analysis.Standard;
/*
软件包管理器:
安装Lucene.Net包-版本4.8.0-Beta0004-预安装
安装包Lucene.Net.Analysis.Common-版本4.8.0-beta0004-预安装
安装Lucene.Net.QueryParser包-版本4.8.0-Beta0004-预安装
*/
名称空间LucennetNumber
{
班级计划
{
静态void Main(字符串[]参数)
{
LuceneVersion MatchVersion=LuceneVersion.LUCENE_48;
使用(var-oDirectory=new-RAMDirectory())
{
var OAAnalyzer=新标准分析仪(匹配版本);
var-oQueryParser=新的多字段queryparser(匹配版本,新[]{“名称”、“高度”、“年龄”},OAAnalyzer);
var oIndexWriterConfig=新索引writerconfig(匹配版本,OAAnalyzer);
var oIndexWriter=newindexwriter(目录,oIndexWriterConfig);
var oSearcherManager=newsearchermanger(oIndexWriter,true,null);
var oAdd=新操作((sName、nAge、nHeight)=>
{
var oDocument=新文档
{
新的文本字段(“name”,sName,Field.Store.YES),
新的Int32Field(“高度”,nHeight,Field.Store.YES),
新的双字段(“age”、nAge、Field.Store.YES),
};
oIndexWriter.UpdateDocument(新术语(“名称”,sName),OdoDocument);
});
oAdd(“约翰·多伊”,24.45,56);
oAdd(“约翰·史密斯”,44.44,64);
oAdd(“迈克·史密斯”,56.65,70);
oIndexWriter.Flush(真,真);
oIndexWriter.Commit();
//
var oSearch=新操作((sQueryString)=>
{
var oQuery=oQueryParser.Parse(sQueryString);
oSearcherManager.MaybeRefreshBlocking();
var oSearcher=oSearcherManager.Acquire();
尝试
{
var-oTopDocs=oSearcher.Search(oQuery,10);
var nTotalHits=oTopDocs.TotalHits;
WriteLine(“总点击数:{0}”,nTotalHits);
foreach(oTopDocs.ScoreDocs中的var oResult)
{
var oDocument=oSearcher.Doc(或结果文件);
var nScore=结果分数;
var sName=oDocument.GetField(“名称”)?.GetStringValue();
var nAge=oDocument.GetField(“年龄”)?.GetNumericValue();
var nHeight=oDocument.GetField(“高度”)?.GetNumericValue();
Console.WriteLine({0:0.00}、{1,15}、{2,8}、{3,8})、nScore、sName、nAge、nHeight);
}
}
捕获(例外e)
{
Console.WriteLine(如ToString());
}
最后
{
oSearcher管理器发布(oSearcher);
oSearcher=null;
}
});
oSearch(“约翰”);
oSearch(“高度:64”);
/*
输出:
点击总数:2
0.20,无名氏,24.45,56
0.20,约翰·史密斯,44.44,64
点击总数:0
*/
}
}
}
}

它与Lucene.Net保存数值的方式(编码形式)有关:

您可以使用
numeriRangeQuery

var oQuery = NumericRangeQuery.NewInt32Range("height", 64, 64, true, true);
使用您试图搜索的数字作为
min
max

另一个选项是使用
术语查询
,并将您的号码转换为
字节参考

BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT32);
NumericUtils.Int32ToPrefixCoded(64, 0, bytes);
Term term = new Term("height", bytes);
var oQuery = new TermQuery(term);
当然,您将无法将查询解析为字符串,但您始终可以创建自己的解析器,在其中组合术语:

BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT32);
NumericUtils.Int32ToPrefixCoded(64, 0, bytes);
Term term = new Term("height", bytes);
// var oQuery = new TermQuery(term);

var oQuery = new BooleanQuery
{
    { new TermQuery(new Term("name", "John")), Occur.SHOULD },
    { new TermQuery(term), Occur.SHOULD }
};
您可以看到如何将查询转换为字符串


虽然我对自己的想法并不完全满意,但它确实满足了我使用查询解析器搜索数字的要求。。。以及原始示例所暗示的文本。我将继续研究如何使用带字符串和数字的StandardQueryParser.SetMultiFields和StandardQueryParser.NumericConfigMap,并在此处编辑/发布任何发现

using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers.Flexible.Standard;
using Lucene.Net.QueryParsers.Flexible.Standard.Config;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Lucene.Net.Support;
using Lucene.Net.Util;
using System;
using System.Globalization;

/*
Package Manager:
Install-Package Lucene.Net -Version 4.8.0-beta00004 -Pre
Install-Package Lucene.Net.Analysis.Common -Version 4.8.0-beta00004 -Pre
Install-Package Lucene.Net.QueryParser -Version 4.8.0-beta00004 -Pre
*/

namespace LuceneNetNumbers
{
    class Program
    {
        static void Main(string[] args)
        {
            LuceneVersion MatchVersion = LuceneVersion.LUCENE_48;

            using (var oDirectory = new RAMDirectory())
            {
                var oAnalyzer = new StandardAnalyzer(MatchVersion);

                //##########
                //##########

                //List of changes...

                //1. Remove this.
                //var oQueryParser = new MultiFieldQueryParser(MatchVersion, new[] { "name", "height", "age" }, oAnalyzer);

                //2. Add the following 6 lines of code.
                var oQueryParser = new StandardQueryParser(oAnalyzer);

                var oNumericConfigMap = new HashMap<string, NumericConfig>();
                oNumericConfigMap.Put("height", new NumericConfig(8, new NumberFormatIgnoreExceptions(CultureInfo.CurrentCulture), NumericType.INT32));
                oNumericConfigMap.Put("age", new NumericConfig(8, new NumberFormatIgnoreExceptions(CultureInfo.CurrentCulture), NumericType.DOUBLE));
                oQueryParser.NumericConfigMap = oNumericConfigMap;

                oQueryParser.SetMultiFields(new[] { "name", "height", "age" });

                //3. Add null as second parameter to StandardQueryParser.Parse below to utilize StandardQueryParser.SetMultiFields

                //4. Create NumberFormatIgnoreExceptions. I was not able to find another way (yet) to get 
                //StandardQueryParser.SetMultiFields and StandardQueryParser.NumericConfigMap to work with 
                //both text and number fields.  I feel like this is a bit of a hack, but it does satisfiy my
                //requirement of using a query parser to search for numbers (and text... implied by example).

                //##########
                //##########

                var oIndexWriterConfig = new IndexWriterConfig(MatchVersion, oAnalyzer);
                var oIndexWriter = new IndexWriter(oDirectory, oIndexWriterConfig);
                var oSearcherManager = new SearcherManager(oIndexWriter, true, null);

                var oAdd = new Action<string, double, int>((sName, nAge, nHeight) =>
                {
                    var oDocument = new Document
                    {
                        new TextField("name", sName, Field.Store.YES),
                        new Int32Field("height", nHeight, Field.Store.YES),
                        new DoubleField("age", nAge, Field.Store.YES),
                    };

                    oIndexWriter.UpdateDocument(new Term("name", sName), oDocument);
                });

                oAdd("John Doe", 24.45, 56);
                oAdd("John Smith", 44.44, 64);
                oAdd("Mike Smith", 56.65, 70);

                oIndexWriter.Flush(true, true);
                oIndexWriter.Commit();

                //

                var oSearch = new Action<string>((sQueryString) =>
                {
                    var oQuery = oQueryParser.Parse(sQueryString, null);
                    oSearcherManager.MaybeRefreshBlocking();
                    var oSearcher = oSearcherManager.Acquire();

                    try
                    {
                        var oTopDocs = oSearcher.Search(oQuery, 10);
                        var nTotalHits = oTopDocs.TotalHits;
                        Console.WriteLine("Total Hits: {0}", nTotalHits);

                        foreach (var oResult in oTopDocs.ScoreDocs)
                        {
                            var oDocument = oSearcher.Doc(oResult.Doc);

                            var nScore = oResult.Score;
                            var sName = oDocument.GetField("name")?.GetStringValue();
                            var nAge = oDocument.GetField("age")?.GetNumericValue();
                            var nHeight = oDocument.GetField("height")?.GetNumericValue();

                            Console.WriteLine("{0:0.00}, {1,15}, {2,8}, {3,8}", nScore, sName, nAge, nHeight);
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.ToString());
                    }
                    finally
                    {
                        oSearcherManager.Release(oSearcher);
                        oSearcher = null;
                    }
                });

                oSearch("john");
                oSearch("height:64");
                oSearch("age:[44.45 TO 56.66]");
                oSearch("height:[70 TO *]");

                /*
                Output:
                Total Hits: 2
                0.12,        John Doe,    24.45,       56
                0.12,      John Smith,    44.44,       64
                Total Hits: 1
                1.00,      John Smith,    44.44,       64
                Total Hits: 1
                1.00,      Mike Smith,    56.65,       70
                Total Hits: 1
                1.00,      Mike Smith,    56.65,       70
                */
            }
        }
    }

    class NumberFormatIgnoreExceptions : NumberFormat
    {
        public NumberFormatIgnoreExceptions(CultureInfo locale) : base(locale)
        {
        }

        public override object Parse(string source)
        {
            var oValue = default(object);

            try { oValue = base.Parse(source); } catch { }

            return oValue;
        }
    }
}
使用Lucene.Net.Analysis.Standard;
使用Lucene.Net.Documents;
使用Lucene.Net.Index;
使用Lucene.Net.QueryParsers.Flexible.Standard;
使用Lucene.Net.QueryParsers.Flexible.Standard.Config;
使用Lucene.Net.Search;
使用Lucene.Net.Store;
使用Lucene.Net.Support;
使用Lucene.Net.Util;
使用制度;
利用制度全球化;
/*
软件包管理器:
安装Lucene.Net包-版本4.8.0-Beta0004-预安装
安装包Lucene.Net.Analysis.Common-版本4.8.0-beta0004-预安装
安装Lucene.Net.QueryParser包-版本4.8.0-Beta0004-预安装
*/
名称空间LucennetNumber
{
班级计划
{
静态void Main(字符串[]参数)
{
LuceneVersion MatchVersion=LuceneVersion.LUCENE_48;
使用(var-oDirectory=new-RAMDirectory())
{
var OAAnalyzer=新标准分析仪(匹配版本);
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers.Flexible.Standard;
using Lucene.Net.QueryParsers.Flexible.Standard.Config;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Lucene.Net.Support;
using Lucene.Net.Util;
using System;
using System.Globalization;

/*
Package Manager:
Install-Package Lucene.Net -Version 4.8.0-beta00004 -Pre
Install-Package Lucene.Net.Analysis.Common -Version 4.8.0-beta00004 -Pre
Install-Package Lucene.Net.QueryParser -Version 4.8.0-beta00004 -Pre
*/

namespace LuceneNetNumbers
{
    class Program
    {
        static void Main(string[] args)
        {
            LuceneVersion MatchVersion = LuceneVersion.LUCENE_48;

            using (var oDirectory = new RAMDirectory())
            {
                var oAnalyzer = new StandardAnalyzer(MatchVersion);

                //##########
                //##########

                //List of changes...

                //1. Remove this.
                //var oQueryParser = new MultiFieldQueryParser(MatchVersion, new[] { "name", "height", "age" }, oAnalyzer);

                //2. Add the following 6 lines of code.
                var oQueryParser = new StandardQueryParser(oAnalyzer);

                var oNumericConfigMap = new HashMap<string, NumericConfig>();
                oNumericConfigMap.Put("height", new NumericConfig(8, new NumberFormatIgnoreExceptions(CultureInfo.CurrentCulture), NumericType.INT32));
                oNumericConfigMap.Put("age", new NumericConfig(8, new NumberFormatIgnoreExceptions(CultureInfo.CurrentCulture), NumericType.DOUBLE));
                oQueryParser.NumericConfigMap = oNumericConfigMap;

                oQueryParser.SetMultiFields(new[] { "name", "height", "age" });

                //3. Add null as second parameter to StandardQueryParser.Parse below to utilize StandardQueryParser.SetMultiFields

                //4. Create NumberFormatIgnoreExceptions. I was not able to find another way (yet) to get 
                //StandardQueryParser.SetMultiFields and StandardQueryParser.NumericConfigMap to work with 
                //both text and number fields.  I feel like this is a bit of a hack, but it does satisfiy my
                //requirement of using a query parser to search for numbers (and text... implied by example).

                //##########
                //##########

                var oIndexWriterConfig = new IndexWriterConfig(MatchVersion, oAnalyzer);
                var oIndexWriter = new IndexWriter(oDirectory, oIndexWriterConfig);
                var oSearcherManager = new SearcherManager(oIndexWriter, true, null);

                var oAdd = new Action<string, double, int>((sName, nAge, nHeight) =>
                {
                    var oDocument = new Document
                    {
                        new TextField("name", sName, Field.Store.YES),
                        new Int32Field("height", nHeight, Field.Store.YES),
                        new DoubleField("age", nAge, Field.Store.YES),
                    };

                    oIndexWriter.UpdateDocument(new Term("name", sName), oDocument);
                });

                oAdd("John Doe", 24.45, 56);
                oAdd("John Smith", 44.44, 64);
                oAdd("Mike Smith", 56.65, 70);

                oIndexWriter.Flush(true, true);
                oIndexWriter.Commit();

                //

                var oSearch = new Action<string>((sQueryString) =>
                {
                    var oQuery = oQueryParser.Parse(sQueryString, null);
                    oSearcherManager.MaybeRefreshBlocking();
                    var oSearcher = oSearcherManager.Acquire();

                    try
                    {
                        var oTopDocs = oSearcher.Search(oQuery, 10);
                        var nTotalHits = oTopDocs.TotalHits;
                        Console.WriteLine("Total Hits: {0}", nTotalHits);

                        foreach (var oResult in oTopDocs.ScoreDocs)
                        {
                            var oDocument = oSearcher.Doc(oResult.Doc);

                            var nScore = oResult.Score;
                            var sName = oDocument.GetField("name")?.GetStringValue();
                            var nAge = oDocument.GetField("age")?.GetNumericValue();
                            var nHeight = oDocument.GetField("height")?.GetNumericValue();

                            Console.WriteLine("{0:0.00}, {1,15}, {2,8}, {3,8}", nScore, sName, nAge, nHeight);
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.ToString());
                    }
                    finally
                    {
                        oSearcherManager.Release(oSearcher);
                        oSearcher = null;
                    }
                });

                oSearch("john");
                oSearch("height:64");
                oSearch("age:[44.45 TO 56.66]");
                oSearch("height:[70 TO *]");

                /*
                Output:
                Total Hits: 2
                0.12,        John Doe,    24.45,       56
                0.12,      John Smith,    44.44,       64
                Total Hits: 1
                1.00,      John Smith,    44.44,       64
                Total Hits: 1
                1.00,      Mike Smith,    56.65,       70
                Total Hits: 1
                1.00,      Mike Smith,    56.65,       70
                */
            }
        }
    }

    class NumberFormatIgnoreExceptions : NumberFormat
    {
        public NumberFormatIgnoreExceptions(CultureInfo locale) : base(locale)
        {
        }

        public override object Parse(string source)
        {
            var oValue = default(object);

            try { oValue = base.Parse(source); } catch { }

            return oValue;
        }
    }
}