Finish QueryParsers.Flexible.Core namespace
Project: http://git-wip-us.apache.org/repos/asf/lucenenet/repo Commit: http://git-wip-us.apache.org/repos/asf/lucenenet/commit/539a6ded Tree: http://git-wip-us.apache.org/repos/asf/lucenenet/tree/539a6ded Diff: http://git-wip-us.apache.org/repos/asf/lucenenet/diff/539a6ded Branch: refs/heads/branch_4x Commit: 539a6ded7d8350ea56a753848831f19581a21777 Parents: c9e9c54 Author: Paul Irwin <[email protected]> Authored: Fri Oct 4 13:32:27 2013 -0400 Committer: Paul Irwin <[email protected]> Committed: Sat Oct 5 16:37:28 2013 -0400 ---------------------------------------------------------------------- .../QueryParsers/Contrib.QueryParsers.csproj | 16 ++ .../Flexible/Core/Nodes/FieldQueryNode.cs | 2 +- .../Flexible/Core/Nodes/IRangeQueryNode.cs | 20 ++ .../Core/Nodes/NoTokenFoundQueryNode.cs | 37 ++++ .../Flexible/Core/Nodes/OpaqueQueryNode.cs | 56 ++++++ .../Flexible/Core/Nodes/OrQueryNode.cs | 58 ++++++ .../Flexible/Core/Nodes/PathQueryNode.cs | 125 ++++++++++++ .../Flexible/Core/Nodes/PhraseSlopQueryNode.cs | 93 +++++++++ .../Flexible/Core/Nodes/ProximityQueryNode.cs | 196 +++++++++++++++++++ .../Flexible/Core/Nodes/QuotedFieldQueryNode.cs | 43 ++++ .../Flexible/Core/Nodes/SlopQueryNode.cs | 93 +++++++++ .../Core/Nodes/TokenizedPhraseQueryNode.cs | 92 +++++++++ .../Flexible/Core/Parser/ISyntaxParser.cs | 2 +- .../Core/Processors/IQueryNodeProcessor.cs | 17 ++ .../NoChildOptimizationQueryNodeProcessor.cs | 52 +++++ .../Core/Processors/QueryNodeProcessor.cs | 131 +++++++++++++ .../Processors/QueryNodeProcessorPipeline.cs | 180 +++++++++++++++++ .../RemoveDeletedQueryNodesProcessor.cs | 82 ++++++++ .../Flexible/Core/QueryParserHelper.cs | 107 ++++++++++ 19 files changed, 1400 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Contrib.QueryParsers.csproj ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Contrib.QueryParsers.csproj b/src/contrib/QueryParsers/Contrib.QueryParsers.csproj index 2fcb669..59815b4 100644 --- a/src/contrib/QueryParsers/Contrib.QueryParsers.csproj +++ b/src/contrib/QueryParsers/Contrib.QueryParsers.csproj @@ -64,6 +64,7 @@ <Compile Include="Flexible\Core\Config\IFieldConfigListener.cs" /> <Compile Include="Flexible\Core\Config\QueryConfigHandler.cs" /> <Compile Include="Flexible\Core\Nodes\FuzzyQueryNode.cs" /> + <Compile Include="Flexible\Core\Nodes\IRangeQueryNode.cs" /> <Compile Include="Flexible\Core\Nodes\ITextableQueryNode.cs" /> <Compile Include="Flexible\Core\Messages\QueryParserMessages.cs" /> <Compile Include="Flexible\Core\Nodes\AndQueryNode.cs" /> @@ -80,12 +81,27 @@ <Compile Include="Flexible\Core\Nodes\MatchAllDocsQueryNode.cs" /> <Compile Include="Flexible\Core\Nodes\MatchNoDocsQueryNode.cs" /> <Compile Include="Flexible\Core\Nodes\ModifierQueryNode.cs" /> + <Compile Include="Flexible\Core\Nodes\NoTokenFoundQueryNode.cs" /> + <Compile Include="Flexible\Core\Nodes\OpaqueQueryNode.cs" /> + <Compile Include="Flexible\Core\Nodes\OrQueryNode.cs" /> + <Compile Include="Flexible\Core\Nodes\PathQueryNode.cs" /> + <Compile Include="Flexible\Core\Nodes\PhraseSlopQueryNode.cs" /> + <Compile Include="Flexible\Core\Nodes\ProximityQueryNode.cs" /> <Compile Include="Flexible\Core\Nodes\QueryNode.cs" /> + <Compile Include="Flexible\Core\Nodes\QuotedFieldQueryNode.cs" /> + <Compile Include="Flexible\Core\Nodes\SlopQueryNode.cs" /> + <Compile Include="Flexible\Core\Nodes\TokenizedPhraseQueryNode.cs" /> <Compile Include="Flexible\Core\Parser\IEscapeQuerySyntax.cs" /> <Compile Include="Flexible\Core\Parser\ISyntaxParser.cs" /> + <Compile Include="Flexible\Core\Processors\IQueryNodeProcessor.cs" /> + <Compile Include="Flexible\Core\Processors\NoChildOptimizationQueryNodeProcessor.cs" /> + <Compile Include="Flexible\Core\Processors\QueryNodeProcessor.cs" /> + <Compile Include="Flexible\Core\Processors\QueryNodeProcessorPipeline.cs" /> + <Compile Include="Flexible\Core\Processors\RemoveDeletedQueryNodesProcessor.cs" /> <Compile Include="Flexible\Core\QueryNodeError.cs" /> <Compile Include="Flexible\Core\QueryNodeException.cs" /> <Compile Include="Flexible\Core\QueryNodeParseException.cs" /> + <Compile Include="Flexible\Core\QueryParserHelper.cs" /> <Compile Include="Flexible\Core\Util\QueryNodeOperation.cs" /> <Compile Include="Flexible\Core\Util\StringUtils.cs" /> <Compile Include="Flexible\Core\Util\UnescapedCharSequence.cs" /> http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Nodes/FieldQueryNode.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Nodes/FieldQueryNode.cs b/src/contrib/QueryParsers/Flexible/Core/Nodes/FieldQueryNode.cs index 41d9ceb..e05841a 100644 --- a/src/contrib/QueryParsers/Flexible/Core/Nodes/FieldQueryNode.cs +++ b/src/contrib/QueryParsers/Flexible/Core/Nodes/FieldQueryNode.cs @@ -35,7 +35,7 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes return escaper.Escape(new StringCharSequenceWrapper(this.text), CultureInfo.CurrentCulture, EscapeQuerySyntax.Type.NORMAL); } - protected ICharSequence GetTermEscapeQuoted(EscapeQuerySyntax escaper) + protected ICharSequence GetTermEscapeQuoted(IEscapeQuerySyntax escaper) { return escaper.Escape(new StringCharSequenceWrapper(this.text), CultureInfo.CurrentCulture, EscapeQuerySyntax.Type.STRING); } http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Nodes/IRangeQueryNode.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Nodes/IRangeQueryNode.cs b/src/contrib/QueryParsers/Flexible/Core/Nodes/IRangeQueryNode.cs new file mode 100644 index 0000000..c9042a5 --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/Nodes/IRangeQueryNode.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes +{ + public interface IRangeQueryNode<T> : IFieldableNode + where T : IFieldValuePairQueryNode<T> + { + T LowerBound { get; } + + T UpperBound { get; } + + bool IsLowerInclusive { get; } + + bool IsUpperInclusive { get; } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Nodes/NoTokenFoundQueryNode.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Nodes/NoTokenFoundQueryNode.cs b/src/contrib/QueryParsers/Flexible/Core/Nodes/NoTokenFoundQueryNode.cs new file mode 100644 index 0000000..f145843 --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/Nodes/NoTokenFoundQueryNode.cs @@ -0,0 +1,37 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Parser; +using Lucene.Net.Support; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes +{ + public class NoTokenFoundQueryNode : DeletedQueryNode + { + public NoTokenFoundQueryNode() + : base() + { + } + + public override ICharSequence ToQueryString(IEscapeQuerySyntax escapeSyntaxParser) + { + return new StringCharSequenceWrapper("[NTF]"); + } + + public override string ToString() + { + return "<notokenfound/>"; + } + + public override IQueryNode CloneTree() + { + NoTokenFoundQueryNode clone = (NoTokenFoundQueryNode)base.CloneTree(); + + // nothing to do here + + return clone; + } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Nodes/OpaqueQueryNode.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Nodes/OpaqueQueryNode.cs b/src/contrib/QueryParsers/Flexible/Core/Nodes/OpaqueQueryNode.cs new file mode 100644 index 0000000..68e8ca7 --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/Nodes/OpaqueQueryNode.cs @@ -0,0 +1,56 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Parser; +using Lucene.Net.Support; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes +{ + public class OpaqueQueryNode : QueryNode + { + private string schema = null; + + private string value = null; + + public OpaqueQueryNode(string schema, string value) + { + this.SetLeaf(true); + + this.schema = schema; + this.value = value; + } + + public override string ToString() + { + return "<opaque schema='" + this.schema + "' value='" + this.value + "'/>"; + } + + public override ICharSequence ToQueryString(IEscapeQuerySyntax escapeSyntaxParser) + { + return new StringCharSequenceWrapper("@" + this.schema + ":'" + this.value + "'"); + } + + public override IQueryNode CloneTree() + { + OpaqueQueryNode clone = (OpaqueQueryNode)base.CloneTree(); + + // .NET Port: shouldn't this have already been done by MemberwiseClone()? + clone.schema = this.schema; + clone.value = this.value; + + return clone; + } + + public string Schema + { + get { return schema; } + } + + public string Value + { + get { return value; } + } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Nodes/OrQueryNode.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Nodes/OrQueryNode.cs b/src/contrib/QueryParsers/Flexible/Core/Nodes/OrQueryNode.cs new file mode 100644 index 0000000..943b3f0 --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/Nodes/OrQueryNode.cs @@ -0,0 +1,58 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Parser; +using Lucene.Net.Support; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes +{ + public class OrQueryNode : BooleanQueryNode + { + public OrQueryNode(IList<IQueryNode> clauses) + : base(clauses) + { + if ((clauses == null) || (clauses.Count == 0)) + { + throw new ArgumentException("OR query must have at least one clause"); + } + } + + public override string ToString() + { + if (Children == null || Children.Count == 0) + return "<boolean operation='or'/>"; + StringBuilder sb = new StringBuilder(); + sb.Append("<boolean operation='or'>"); + foreach (IQueryNode child in Children) + { + sb.Append("\n"); + sb.Append(child.ToString()); + + } + sb.Append("\n</boolean>"); + return sb.ToString(); + } + + public override ICharSequence ToQueryString(IEscapeQuerySyntax escapeSyntaxParser) + { + if (Children == null || Children.Count == 0) + return new StringCharSequenceWrapper(""); + + StringBuilder sb = new StringBuilder(); + String filler = ""; + foreach (IQueryNode child in Children) + { + sb.Append(filler).Append(child.ToQueryString(escapeSyntaxParser)); + filler = " OR "; + } + + // in case is root or the parent is a group node avoid parenthesis + if ((Parent != null && Parent is GroupQueryNode) || IsRoot) + return new StringCharSequenceWrapper(sb.ToString()); + else + return new StringCharSequenceWrapper("( " + sb.ToString() + " )"); + } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Nodes/PathQueryNode.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Nodes/PathQueryNode.cs b/src/contrib/QueryParsers/Flexible/Core/Nodes/PathQueryNode.cs new file mode 100644 index 0000000..c8d55de --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/Nodes/PathQueryNode.cs @@ -0,0 +1,125 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Parser; +using Lucene.Net.Support; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes +{ + public class PathQueryNode : QueryNode + { + public class QueryText : ICloneable + { + string value = null; + int begin; + int end; + + public QueryText(string value, int begin, int end) + { + this.value = value; + this.begin = begin; + this.end = end; + } + + public string Value + { + get { return value; } + } + + public int Begin + { + get { return begin; } + } + + public int End + { + get { return end; } + } + + public override string ToString() + { + return value + ", " + begin + ", " + end; + } + + public object Clone() + { + return this.MemberwiseClone(); + } + } + + private IList<QueryText> values = null; + + public PathQueryNode(IList<QueryText> pathElements) + { + this.values = pathElements; + if (pathElements.Count <= 1) + { + // this should not happen + throw new ArgumentException("PathQuerynode requires more 2 or more path elements."); + } + } + + public IList<QueryText> PathElements + { + get { return values; } + set { this.values = value; } + } + + public QueryText GetPathElement(int index) + { + return values[index]; + } + + public string FirstPathElement + { + get { return values[0].Value; } + } + + public IList<QueryText> GetPathElements(int startIndex) + { + IList<PathQueryNode.QueryText> rValues = new List<PathQueryNode.QueryText>(); + for (int i = startIndex; i < this.values.Count; i++) + { + try + { + rValues.Add((QueryText)this.values[i].Clone()); + } + catch (NotSupportedException) + { + // this will not happen + } + } + return rValues; + } + + private string PathString + { + get + { + StringBuilder path = new StringBuilder(); + + foreach (QueryText pathelement in values) + { + path.Append("/").Append(pathelement.Value); + } + return path.ToString(); + } + } + + public override ICharSequence ToQueryString(IEscapeQuerySyntax escaper) + { + StringBuilder path = new StringBuilder(); + path.Append("/").Append(FirstPathElement); + + foreach (QueryText pathelement in GetPathElements(1)) + { + ICharSequence value = escaper.Escape(new StringCharSequenceWrapper(pathelement.Value), CultureInfo.CurrentCulture, EscapeQuerySyntax.Type.STRING); + path.Append("/\"").Append(value).Append("\""); + } + return new StringCharSequenceWrapper(path.ToString()); + } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Nodes/PhraseSlopQueryNode.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Nodes/PhraseSlopQueryNode.cs b/src/contrib/QueryParsers/Flexible/Core/Nodes/PhraseSlopQueryNode.cs new file mode 100644 index 0000000..0ea1974 --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/Nodes/PhraseSlopQueryNode.cs @@ -0,0 +1,93 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Messages; +using Lucene.Net.QueryParsers.Flexible.Core.Parser; +using Lucene.Net.QueryParsers.Flexible.Messages; +using Lucene.Net.Support; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes +{ + public class PhraseSlopQueryNode : QueryNode, IFieldableNode + { + private int value = 0; + + public PhraseSlopQueryNode(IQueryNode query, int value) + { + if (query == null) + { + throw new QueryNodeError(new Message(QueryParserMessages.NODE_ACTION_NOT_SUPPORTED, "query", "null")); + } + + this.value = value; + SetLeaf(false); + Allocate(); + Add(query); + } + + public IQueryNode Child + { + get { return Children[0]; } + } + + public int Value + { + get { return value; } + } + + private string ValueString + { + get + { + // .NET Port: java code here was doing some seemingly unnecessary checks + // that seemed like cruft left over from float code + return value.ToString(); + } + } + + public override string ToString() + { + return "<phraseslop value='" + ValueString + "'>" + "\n" + Child.ToString() + "\n</phraseslop>"; + } + + public override ICharSequence ToQueryString(IEscapeQuerySyntax escapeSyntaxParser) + { + if (Child == null) + return new StringCharSequenceWrapper(""); + return new StringCharSequenceWrapper(Child.ToQueryString(escapeSyntaxParser) + "~" + ValueString); + } + + public override IQueryNode CloneTree() + { + PhraseSlopQueryNode clone = (PhraseSlopQueryNode)base.CloneTree(); + + clone.value = this.value; + + return clone; + } + + public string Field + { + get + { + IQueryNode child = Child; + + if (child is IFieldableNode) + return ((IFieldableNode)child).Field; + + return null; + } + set + { + IQueryNode child = Child; + + if (child is IFieldableNode) + { + ((IFieldableNode)child).Field = value; + } + } + } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Nodes/ProximityQueryNode.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Nodes/ProximityQueryNode.cs b/src/contrib/QueryParsers/Flexible/Core/Nodes/ProximityQueryNode.cs new file mode 100644 index 0000000..7fadda6 --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/Nodes/ProximityQueryNode.cs @@ -0,0 +1,196 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Messages; +using Lucene.Net.QueryParsers.Flexible.Core.Parser; +using Lucene.Net.QueryParsers.Flexible.Messages; +using Lucene.Net.Support; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes +{ + public class ProximityQueryNode : BooleanQueryNode + { + public enum Type + { + PARAGRAPH, + SENTENCE, + NUMBER + } + + // .NET Port: This is necessary as enums are value types in .NET and can't have override/abstract methods + public static string TypeToQueryString(Type t) + { + switch (t) + { + case Type.PARAGRAPH: + return "WITHIN PARAGRAPH"; + case Type.SENTENCE: + return "WITHIN SENTENCE"; + case Type.NUMBER: + return "WITHIN"; + default: + throw new InvalidOperationException("Not supported"); + } + } + + public class ProximityType + { + internal int pDistance = 0; + + internal Type? pType = null; + + public ProximityType(Type type) + : this(type, 0) + { + } + + public ProximityType(Type type, int distance) + { + this.pType = type; + this.pDistance = distance; + } + } + + private Type proximityType = Type.SENTENCE; + private int distance = -1; + private bool inorder = false; + private string field = null; + + public ProximityQueryNode(IList<IQueryNode> clauses, string field, Type type, int distance, bool inorder) + : base(clauses) + { + SetLeaf(false); + this.proximityType = type; + this.inorder = inorder; + this.field = field; + if (type == Type.NUMBER) + { + if (distance <= 0) + { + throw new QueryNodeError(new Message(QueryParserMessages.PARAMETER_VALUE_NOT_SUPPORTED, "distance", distance)); + + } + else + { + this.distance = distance; + } + + } + ClearFields(clauses, field); + } + + public ProximityQueryNode(IList<IQueryNode> clauses, string field, Type type, bool inorder) + : this(clauses, field, type, -1, inorder) + { + } + + private static void ClearFields(IList<IQueryNode> nodes, string field) + { + if (nodes == null || nodes.Count == 0) + return; + + foreach (IQueryNode clause in nodes) + { + if (clause is FieldQueryNode) + { + ((FieldQueryNode)clause).toQueryStringIgnoreFields = true; + ((FieldQueryNode)clause).Field = field; + } + } + } + + public Type ProximityTypeValue + { + get + { + return this.proximityType; + } + } + + public override string ToString() + { + String distanceSTR = ((this.distance == -1) ? ("") + : (" distance='" + this.distance) + "'"); + + if (Children == null || Children.Count == 0) + return "<proximity field='" + this.field + "' inorder='" + this.inorder + + "' type='" + this.proximityType.ToString() + "'" + distanceSTR + + "/>"; + StringBuilder sb = new StringBuilder(); + sb.Append("<proximity field='" + this.field + "' inorder='" + this.inorder + + "' type='" + this.proximityType.ToString() + "'" + distanceSTR + ">"); + foreach (IQueryNode child in Children) + { + sb.Append("\n"); + sb.Append(child.ToString()); + } + sb.Append("\n</proximity>"); + return sb.ToString(); + } + + public override ICharSequence ToQueryString(IEscapeQuerySyntax escapeSyntaxParser) + { + String withinSTR = TypeToQueryString(this.proximityType) + + ((this.distance == -1) ? ("") : (" " + this.distance)) + + ((this.inorder) ? (" INORDER") : ("")); + + StringBuilder sb = new StringBuilder(); + if (Children == null || Children.Count == 0) + { + // no children case + } + else + { + String filler = ""; + foreach (IQueryNode child in Children) + { + sb.Append(filler).Append(child.ToQueryString(escapeSyntaxParser)); + filler = " "; + } + } + + if (IsDefaultField(this.field)) + { + return new StringCharSequenceWrapper("( " + sb.ToString() + " ) " + withinSTR); + } + else + { + return new StringCharSequenceWrapper(this.field + ":(( " + sb.ToString() + " ) " + withinSTR + ")"); + } + } + + public override IQueryNode CloneTree() + { + ProximityQueryNode clone = (ProximityQueryNode)base.CloneTree(); + + clone.proximityType = this.proximityType; + clone.distance = this.distance; + clone.field = this.field; + + return clone; + } + + public int Distance + { + get { return this.distance; } + } + + public string Field + { + get { return this.field; } + set { this.field = value; } + } + + public string FieldAsString + { + get { return this.field; } + } + + public bool IsInOrder + { + get { return this.inorder; } + } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Nodes/QuotedFieldQueryNode.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Nodes/QuotedFieldQueryNode.cs b/src/contrib/QueryParsers/Flexible/Core/Nodes/QuotedFieldQueryNode.cs new file mode 100644 index 0000000..2af7e36 --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/Nodes/QuotedFieldQueryNode.cs @@ -0,0 +1,43 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Parser; +using Lucene.Net.Support; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes +{ + public class QuotedFieldQueryNode : FieldQueryNode + { + public QuotedFieldQueryNode(string field, string text, int begin, int end) + : base(field, text, begin, end) + { + } + + public override ICharSequence ToQueryString(IEscapeQuerySyntax escaper) + { + if (IsDefaultField(this.field)) + { + return new StringCharSequenceWrapper("\"" + GetTermEscapeQuoted(escaper) + "\""); + } + else + { + return new StringCharSequenceWrapper(this.field + ":" + "\"" + GetTermEscapeQuoted(escaper) + "\""); + } + } + + public override string ToString() + { + return "<quotedfield start='" + this.begin + "' end='" + this.end + + "' field='" + this.field + "' term='" + this.text + "'/>"; + } + + public override IQueryNode CloneTree() + { + QuotedFieldQueryNode clone = (QuotedFieldQueryNode)base.CloneTree(); + // nothing to do here + return clone; + } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Nodes/SlopQueryNode.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Nodes/SlopQueryNode.cs b/src/contrib/QueryParsers/Flexible/Core/Nodes/SlopQueryNode.cs new file mode 100644 index 0000000..b2ce8f2 --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/Nodes/SlopQueryNode.cs @@ -0,0 +1,93 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Messages; +using Lucene.Net.QueryParsers.Flexible.Core.Parser; +using Lucene.Net.QueryParsers.Flexible.Messages; +using Lucene.Net.Support; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes +{ + public class SlopQueryNode : QueryNode, IFieldableNode + { + private int value = 0; + + public SlopQueryNode(IQueryNode query, int value) + { + if (query == null) + { + throw new QueryNodeError(new Message(QueryParserMessages.NODE_ACTION_NOT_SUPPORTED, "query", "null")); + } + + this.value = value; + SetLeaf(false); + Allocate(); + Add(query); + } + + public IQueryNode Child + { + get + { + return Children[0]; + } + } + + public int Value + { + get { return value; } + } + + public string ValueString + { + get { return value.ToString(); } + } + + public override string ToString() + { + return "<slop value='" + ValueString + "'>" + "\n" + Child.ToString() + "\n</slop>"; + } + + public override ICharSequence ToQueryString(IEscapeQuerySyntax escapeSyntaxParser) + { + if (Child == null) + return new StringCharSequenceWrapper(""); + return new StringCharSequenceWrapper(Child.ToQueryString(escapeSyntaxParser) + "~" + ValueString); + } + + public override IQueryNode CloneTree() + { + SlopQueryNode clone = (SlopQueryNode)base.CloneTree(); + + clone.value = this.value; + + return clone; + } + + public string Field + { + get + { + IQueryNode child = Child; + + if (child is IFieldableNode) + { + return ((IFieldableNode)child).Field; + } + + return null; + } + set + { + IQueryNode child = Child; + + if (child is IFieldableNode) + { + ((IFieldableNode)child).Field = value; + } + } + } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Nodes/TokenizedPhraseQueryNode.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Nodes/TokenizedPhraseQueryNode.cs b/src/contrib/QueryParsers/Flexible/Core/Nodes/TokenizedPhraseQueryNode.cs new file mode 100644 index 0000000..d42443e --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/Nodes/TokenizedPhraseQueryNode.cs @@ -0,0 +1,92 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Parser; +using Lucene.Net.Support; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes +{ + public class TokenizedPhraseQueryNode : QueryNode, IFieldableNode + { + public TokenizedPhraseQueryNode() + { + SetLeaf(false); + Allocate(); + } + + public override string ToString() + { + if (Children == null || Children.Count == 0) + return "<tokenizedphrase/>"; + StringBuilder sb = new StringBuilder(); + sb.Append("<tokenizedtphrase>"); + foreach (IQueryNode child in Children) + { + sb.Append("\n"); + sb.Append(child.ToString()); + } + sb.Append("\n</tokenizedphrase>"); + return sb.ToString(); + } + + public override ICharSequence ToQueryString(IEscapeQuerySyntax escapeSyntaxParser) + { + if (Children == null || Children.Count == 0) + return new StringCharSequenceWrapper(""); + + StringBuilder sb = new StringBuilder(); + String filler = ""; + foreach (IQueryNode child in Children) + { + sb.Append(filler).Append(child.ToQueryString(escapeSyntaxParser)); + filler = ","; + } + + return new StringCharSequenceWrapper("[TP[" + sb.ToString() + "]]"); + } + + public override IQueryNode CloneTree() + { + TokenizedPhraseQueryNode clone = (TokenizedPhraseQueryNode)base.CloneTree(); + + // nothing to do + + return clone; + } + + public string Field + { + get + { + IList<IQueryNode> children = Children; + + if (children == null || children.Count == 0) + { + return null; + + } + else + { + return ((IFieldableNode)children[0]).Field; + } + } + set + { + IList<IQueryNode> children = Children; + + if (children != null) + { + foreach (IQueryNode child in Children) + { + if (child is IFieldableNode) + { + ((IFieldableNode)child).Field = value; + } + } + } + } + } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Parser/ISyntaxParser.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Parser/ISyntaxParser.cs b/src/contrib/QueryParsers/Flexible/Core/Parser/ISyntaxParser.cs index b59540e..4a56a44 100644 --- a/src/contrib/QueryParsers/Flexible/Core/Parser/ISyntaxParser.cs +++ b/src/contrib/QueryParsers/Flexible/Core/Parser/ISyntaxParser.cs @@ -10,6 +10,6 @@ namespace Lucene.Net.QueryParsers.Flexible.Core.Parser { public interface ISyntaxParser { - IQueryNode Parse(ICharSequence query, ICharSequence field); + IQueryNode Parse(string query, string field); } } http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Processors/IQueryNodeProcessor.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Processors/IQueryNodeProcessor.cs b/src/contrib/QueryParsers/Flexible/Core/Processors/IQueryNodeProcessor.cs new file mode 100644 index 0000000..c2cd9a4 --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/Processors/IQueryNodeProcessor.cs @@ -0,0 +1,17 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Config; +using Lucene.Net.QueryParsers.Flexible.Core.Nodes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core.Processors +{ + public interface IQueryNodeProcessor + { + IQueryNode Process(IQueryNode queryTree); + + QueryConfigHandler QueryConfigHandler { get; set; } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Processors/NoChildOptimizationQueryNodeProcessor.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Processors/NoChildOptimizationQueryNodeProcessor.cs b/src/contrib/QueryParsers/Flexible/Core/Processors/NoChildOptimizationQueryNodeProcessor.cs new file mode 100644 index 0000000..3390b2c --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/Processors/NoChildOptimizationQueryNodeProcessor.cs @@ -0,0 +1,52 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Nodes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core.Processors +{ + public class NoChildOptimizationQueryNodeProcessor : QueryNodeProcessor + { + public NoChildOptimizationQueryNodeProcessor() + { + // empty constructor + } + + protected override IQueryNode PostProcessNode(IQueryNode node) + { + if (node is BooleanQueryNode || node is BoostQueryNode + || node is TokenizedPhraseQueryNode + || node is ModifierQueryNode) + { + IList<IQueryNode> children = node.Children; + + if (children != null && children.Count > 0) + { + foreach (IQueryNode child in children) + { + if (!(child is DeletedQueryNode)) + { + return node; + } + } + } + + return new MatchNoDocsQueryNode(); + } + + return node; + } + + protected override IQueryNode PreProcessNode(IQueryNode node) + { + return node; + } + + protected override IList<IQueryNode> SetChildrenOrder(IList<IQueryNode> children) + { + return children; + } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Processors/QueryNodeProcessor.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Processors/QueryNodeProcessor.cs b/src/contrib/QueryParsers/Flexible/Core/Processors/QueryNodeProcessor.cs new file mode 100644 index 0000000..98def49 --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/Processors/QueryNodeProcessor.cs @@ -0,0 +1,131 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Config; +using Lucene.Net.QueryParsers.Flexible.Core.Nodes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core.Processors +{ + public abstract class QueryNodeProcessor : IQueryNodeProcessor + { + private List<ChildrenList> childrenListPool = new List<ChildrenList>(); + + private QueryConfigHandler queryConfig; + + public QueryNodeProcessor() + { + // empty constructor + } + + public QueryNodeProcessor(QueryConfigHandler queryConfigHandler) + { + this.queryConfig = queryConfigHandler; + } + + public virtual IQueryNode Process(IQueryNode queryTree) + { + return ProcessIteration(queryTree); + } + + private IQueryNode ProcessIteration(IQueryNode queryTree) + { + queryTree = PreProcessNode(queryTree); + + ProcessChildren(queryTree); + + queryTree = PostProcessNode(queryTree); + + return queryTree; + } + + protected void ProcessChildren(IQueryNode queryTree) + { + IList<IQueryNode> children = queryTree.Children; + ChildrenList newChildren; + + if (children != null && children.Count > 0) + { + newChildren = AllocateChildrenList(); + + try + { + IQueryNode child; + + // .NET Port: can't modify range variable, changed to for loop + for (int i = 0; i < children.Count; i++) + { + child = children[i]; + + child = ProcessIteration(child); + + if (child == null) + { + throw new NullReferenceException(); + } + + newChildren.Add(child); + } + + IList<IQueryNode> orderedChildrenList = SetChildrenOrder(newChildren); + + queryTree.Set(orderedChildrenList); + } + finally + { + newChildren.beingUsed = false; + } + } + } + + private ChildrenList AllocateChildrenList() + { + ChildrenList list = null; + + foreach (ChildrenList auxList in this.childrenListPool) + { + if (!auxList.beingUsed) + { + list = auxList; + list.Clear(); + + break; + } + } + + if (list == null) + { + list = new ChildrenList(); + this.childrenListPool.Add(list); + } + + list.beingUsed = true; + + return list; + } + + public QueryConfigHandler QueryConfigHandler + { + get + { + return this.queryConfig; + } + set + { + this.queryConfig = value; + } + } + + protected abstract IQueryNode PreProcessNode(IQueryNode node); + + protected abstract IQueryNode PostProcessNode(IQueryNode node); + + protected abstract IList<IQueryNode> SetChildrenOrder(IList<IQueryNode> children); + + private class ChildrenList : List<IQueryNode> + { + internal bool beingUsed; + } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Processors/QueryNodeProcessorPipeline.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Processors/QueryNodeProcessorPipeline.cs b/src/contrib/QueryParsers/Flexible/Core/Processors/QueryNodeProcessorPipeline.cs new file mode 100644 index 0000000..d674ce9 --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/Processors/QueryNodeProcessorPipeline.cs @@ -0,0 +1,180 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Config; +using Lucene.Net.QueryParsers.Flexible.Core.Nodes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core.Processors +{ + public class QueryNodeProcessorPipeline : IQueryNodeProcessor, IList<IQueryNodeProcessor> + { + private List<IQueryNodeProcessor> processors = new List<IQueryNodeProcessor>(); + + private QueryConfigHandler queryConfig; + + public QueryNodeProcessorPipeline() + { + // empty constructor + } + + public QueryNodeProcessorPipeline(QueryConfigHandler queryConfigHandler) + { + this.queryConfig = queryConfigHandler; + } + + public QueryConfigHandler QueryConfigHandler + { + get + { + return this.queryConfig; + } + set + { + this.queryConfig = value; + + foreach (IQueryNodeProcessor processor in this.processors) + { + processor.QueryConfigHandler = this.queryConfig; + } + } + } + + public IQueryNode Process(IQueryNode queryTree) + { + foreach (IQueryNodeProcessor processor in this.processors) + { + queryTree = processor.Process(queryTree); + } + + return queryTree; + } + + public void Add(IQueryNodeProcessor processor) + { + this.processors.Add(processor); + + processor.QueryConfigHandler = this.queryConfig; + } + + public void Insert(int index, IQueryNodeProcessor processor) + { + this.processors.Insert(index, processor); + processor.QueryConfigHandler = this.queryConfig; + } + + public bool AddAll(ICollection<IQueryNodeProcessor> c) + { + this.processors.AddRange(c); + + foreach (IQueryNodeProcessor processor in c) + { + processor.QueryConfigHandler = this.queryConfig; + } + + return c.Count > 0; + } + + public bool AddAll(int index, ICollection<IQueryNodeProcessor> c) + { + this.processors.InsertRange(index, c); + + foreach (IQueryNodeProcessor processor in c) + { + processor.QueryConfigHandler = this.queryConfig; + } + + return c.Count > 0; + } + + public void Clear() + { + this.processors.Clear(); + } + + public bool Contains(IQueryNodeProcessor item) + { + return this.processors.Contains(item); + } + + public bool ContainsAll(ICollection<IQueryNodeProcessor> c) + { + foreach (var processor in c) + { + if (!this.processors.Contains(processor)) + return false; + } + + return true; + } + + public IQueryNodeProcessor this[int index] + { + get + { + return this.processors[index]; + } + set + { + IQueryNodeProcessor oldProcessor = (this.processors.Count > index) ? this.processors[index] : value; + this.processors[index] = value; + + if (oldProcessor != value) + { + value.QueryConfigHandler = this.queryConfig; + } + } + } + + public int IndexOf(IQueryNodeProcessor item) + { + return this.processors.IndexOf(item); + } + + public bool IsEmpty + { + get { return this.processors.Count == 0; } + } + + public IEnumerator<IQueryNodeProcessor> GetEnumerator() + { + return this.processors.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public int LastIndexOf(IQueryNodeProcessor o) + { + return this.processors.LastIndexOf(o); + } + + public bool Remove(IQueryNodeProcessor item) + { + return this.processors.Remove(item); + } + + public void RemoveAt(int index) + { + this.processors.RemoveAt(index); + } + + public int Count + { + get { return this.processors.Count; } + } + + public bool IsReadOnly + { + get { return false; } + } + + public void CopyTo(IQueryNodeProcessor[] array, int arrayIndex) + { + ((IList<IQueryNodeProcessor>)this.processors).CopyTo(array, arrayIndex); + } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/Processors/RemoveDeletedQueryNodesProcessor.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/Processors/RemoveDeletedQueryNodesProcessor.cs b/src/contrib/QueryParsers/Flexible/Core/Processors/RemoveDeletedQueryNodesProcessor.cs new file mode 100644 index 0000000..106f075 --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/Processors/RemoveDeletedQueryNodesProcessor.cs @@ -0,0 +1,82 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Nodes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core.Processors +{ + public class RemoveDeletedQueryNodesProcessor : QueryNodeProcessor + { + public RemoveDeletedQueryNodesProcessor() + { + // empty constructor + } + + public override IQueryNode Process(IQueryNode queryTree) + { + queryTree = base.Process(queryTree); + + if (queryTree is DeletedQueryNode + && !(queryTree is MatchNoDocsQueryNode)) + { + return new MatchNoDocsQueryNode(); + } + + return queryTree; + } + + protected override IQueryNode PostProcessNode(IQueryNode node) + { + if (!node.IsLeaf) + { + IList<IQueryNode> children = node.Children; + bool removeBoolean = false; + + if (children == null || children.Count == 0) + { + removeBoolean = true; + } + else + { + removeBoolean = true; + + foreach (IQueryNode child in children) + { + if (!(child is DeletedQueryNode)) + { + removeBoolean = false; + break; + } + } + } + + if (removeBoolean) + { + return new DeletedQueryNode(); + } + } + + return node; + } + + protected override IList<IQueryNode> SetChildrenOrder(IList<IQueryNode> children) + { + for (int i = 0; i < children.Count; i++) + { + if (children[i] is DeletedQueryNode) + { + children.RemoveAt(i--); + } + } + + return children; + } + + protected override IQueryNode PreProcessNode(IQueryNode node) + { + return node; + } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/539a6ded/src/contrib/QueryParsers/Flexible/Core/QueryParserHelper.cs ---------------------------------------------------------------------- diff --git a/src/contrib/QueryParsers/Flexible/Core/QueryParserHelper.cs b/src/contrib/QueryParsers/Flexible/Core/QueryParserHelper.cs new file mode 100644 index 0000000..97fdd7c --- /dev/null +++ b/src/contrib/QueryParsers/Flexible/Core/QueryParserHelper.cs @@ -0,0 +1,107 @@ +using Lucene.Net.QueryParsers.Flexible.Core.Builders; +using Lucene.Net.QueryParsers.Flexible.Core.Config; +using Lucene.Net.QueryParsers.Flexible.Core.Nodes; +using Lucene.Net.QueryParsers.Flexible.Core.Parser; +using Lucene.Net.QueryParsers.Flexible.Core.Processors; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lucene.Net.QueryParsers.Flexible.Core +{ + public class QueryParserHelper + { + private IQueryNodeProcessor processor; + + private ISyntaxParser syntaxParser; + + private IQueryBuilder builder; + + private QueryConfigHandler config; + + public QueryParserHelper(QueryConfigHandler queryConfigHandler, ISyntaxParser syntaxParser, IQueryNodeProcessor processor, IQueryBuilder builder) + { + this.syntaxParser = syntaxParser; + this.config = queryConfigHandler; + this.processor = processor; + this.builder = builder; + + if (processor != null) + { + processor.QueryConfigHandler = queryConfigHandler; + } + } + + public IQueryNodeProcessor QueryNodeProcessor + { + get + { + return processor; + } + set + { + this.processor = value; + this.processor.QueryConfigHandler = QueryConfigHandler; + } + } + + public ISyntaxParser SyntaxParser + { + get { return syntaxParser; } + set + { + if (value == null) + { + throw new ArgumentException("textParser should not be null!"); + } + + this.syntaxParser = value; + } + } + + public IQueryBuilder QueryBuilder + { + get { return builder; } + set + { + if (value == null) + { + throw new ArgumentException("queryBuilder should not be null!"); + } + + this.builder = value; + } + } + + public QueryConfigHandler QueryConfigHandler + { + get { return config; } + set + { + this.config = value; + IQueryNodeProcessor processor = QueryNodeProcessor; + + if (processor != null) + { + processor.QueryConfigHandler = config; + } + } + } + + public object Parse(string query, string defaultField) + { + IQueryNode queryTree = SyntaxParser.Parse(query, defaultField); + + IQueryNodeProcessor processor = QueryNodeProcessor; + + if (processor != null) + { + queryTree = processor.Process(queryTree); + } + + return QueryBuilder.Build(queryTree); + } + } +}
