You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ni...@apache.org on 2016/12/06 15:11:40 UTC
[05/58] lucenenet git commit: WIP on QueryParsers.Flexible
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/FuzzyQueryNodeProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/FuzzyQueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/FuzzyQueryNodeProcessor.cs
new file mode 100644
index 0000000..59fc57d
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/FuzzyQueryNodeProcessor.cs
@@ -0,0 +1,75 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Config;
+using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using Lucene.Net.QueryParsers.Flexible.Core.Processors;
+using Lucene.Net.QueryParsers.Flexible.Standard.Config;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Standard.Processors
+{
+ /// <summary>
+ /// This processor iterates the query node tree looking for every
+ /// {@link FuzzyQueryNode}, when this kind of node is found, it checks on the
+ /// query configuration for
+ /// {@link ConfigurationKeys#FUZZY_CONFIG}, gets the
+ /// fuzzy prefix length and default similarity from it and set to the fuzzy node.
+ /// For more information about fuzzy prefix length check: {@link FuzzyQuery}.
+ /// </summary>
+ /// <seealso cref="ConfigurationKeys#FUZZY_CONFIG"/>
+ /// <seealso cref="FuzzyQuery"/>
+ /// <seealso cref="FuzzyQueryNode"/>
+ public class FuzzyQueryNodeProcessor : QueryNodeProcessorImpl
+ {
+
+ protected override IQueryNode PostProcessNode(IQueryNode node)
+ {
+
+ return node;
+
+ }
+
+
+ protected override IQueryNode PreProcessNode(IQueryNode node)
+ {
+
+ if (node is FuzzyQueryNode)
+ {
+ FuzzyQueryNode fuzzyNode = (FuzzyQueryNode)node;
+ QueryConfigHandler config = GetQueryConfigHandler();
+
+ FuzzyConfig fuzzyConfig = null;
+
+ if (config != null && (fuzzyConfig = config.Get(ConfigurationKeys.FUZZY_CONFIG)) != null)
+ {
+ fuzzyNode.SetPrefixLength(fuzzyConfig.GetPrefixLength());
+
+ if (fuzzyNode.GetSimilarity() < 0)
+ {
+ fuzzyNode.SetSimilarity(fuzzyConfig.GetMinSimilarity());
+ }
+
+ }
+ else if (fuzzyNode.GetSimilarity() < 0)
+ {
+ throw new ArgumentException("No FUZZY_CONFIG set in the config");
+ }
+
+ }
+
+ return node;
+
+ }
+
+
+ protected override IList<IQueryNode> SetChildrenOrder(IList<IQueryNode> children)
+ {
+
+ return children;
+
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/GroupQueryNodeProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/GroupQueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/GroupQueryNodeProcessor.cs
new file mode 100644
index 0000000..d13f79e
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/GroupQueryNodeProcessor.cs
@@ -0,0 +1,240 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Config;
+using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using Lucene.Net.QueryParsers.Flexible.Core.Processors;
+using Lucene.Net.QueryParsers.Flexible.Standard.Config;
+using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Standard.Processors
+{
+ /// <summary>
+ /// The {@link SyntaxParser}
+ /// generates query node trees that consider the boolean operator precedence, but
+ /// Lucene current syntax does not support boolean precedence, so this processor
+ /// remove all the precedence and apply the equivalent modifier according to the
+ /// boolean operation defined on an specific query node.
+ /// <para/>
+ /// If there is a {@link GroupQueryNode} in the query node tree, the query node
+ /// tree is not merged with the one above it.
+ /// <para/>
+ /// Example: TODO: describe a good example to show how this processor works
+ /// </summary>
+ /// <seealso cref="StandardQueryConfigHandler"/>
+ [Obsolete("Use BooleanQuery2ModifierNodeProcessor instead")]
+ public class GroupQueryNodeProcessor : IQueryNodeProcessor
+ {
+ private List<IQueryNode> queryNodeList;
+
+ private bool latestNodeVerified;
+
+ private QueryConfigHandler queryConfig;
+
+ private bool usingAnd = false;
+
+ public GroupQueryNodeProcessor()
+ {
+ // empty constructor
+ }
+
+
+ public virtual IQueryNode Process(IQueryNode queryTree)
+ {
+ Operator? defaultOperator = GetQueryConfigHandler().Get(ConfigurationKeys.DEFAULT_OPERATOR);
+
+ if (defaultOperator == null)
+ {
+ throw new ArgumentException(
+ "DEFAULT_OPERATOR should be set on the QueryConfigHandler");
+ }
+
+ this.usingAnd = Operator.AND == defaultOperator;
+
+ if (queryTree is GroupQueryNode)
+ {
+ queryTree = ((GroupQueryNode)queryTree).GetChild();
+ }
+
+ this.queryNodeList = new List<IQueryNode>();
+ this.latestNodeVerified = false;
+ ReadTree(queryTree);
+
+ List<IQueryNode> actualQueryNodeList = this.queryNodeList;
+
+ for (int i = 0; i < actualQueryNodeList.Count; i++)
+ {
+ IQueryNode node = actualQueryNodeList[i];
+
+ if (node is GroupQueryNode)
+ {
+ actualQueryNodeList[i] = Process(node);
+ }
+
+ }
+
+ this.usingAnd = false;
+
+ if (queryTree is BooleanQueryNode)
+ {
+ queryTree.Set(actualQueryNodeList);
+
+ return queryTree;
+
+ }
+ else
+ {
+ return new BooleanQueryNode(actualQueryNodeList);
+ }
+
+ }
+
+ /**
+ */
+ private IQueryNode ApplyModifier(IQueryNode node, IQueryNode parent)
+ {
+
+ if (this.usingAnd)
+ {
+
+ if (parent is OrQueryNode)
+ {
+
+ if (node is ModifierQueryNode)
+ {
+
+ ModifierQueryNode modNode = (ModifierQueryNode)node;
+
+ if (modNode.GetModifier() == Modifier.MOD_REQ)
+ {
+ return modNode.GetChild();
+ }
+
+ }
+
+ }
+ else
+ {
+
+ if (node is ModifierQueryNode)
+ {
+
+ ModifierQueryNode modNode = (ModifierQueryNode)node;
+
+ if (modNode.GetModifier() == Modifier.MOD_NONE)
+ {
+ return new BooleanModifierNode(modNode.GetChild(), Modifier.MOD_REQ);
+ }
+
+ }
+ else
+ {
+ return new BooleanModifierNode(node, Modifier.MOD_REQ);
+ }
+
+ }
+
+ }
+ else
+ {
+
+ if (node.GetParent() is AndQueryNode)
+ {
+
+ if (node is ModifierQueryNode)
+ {
+
+ ModifierQueryNode modNode = (ModifierQueryNode)node;
+
+ if (modNode.GetModifier() == Modifier.MOD_NONE)
+ {
+ return new BooleanModifierNode(modNode.GetChild(), Modifier.MOD_REQ);
+ }
+
+ }
+ else
+ {
+ return new BooleanModifierNode(node, Modifier.MOD_REQ);
+ }
+
+ }
+
+ }
+
+ return node;
+
+ }
+
+ private void ReadTree(IQueryNode node)
+ {
+
+ if (node is BooleanQueryNode)
+ {
+ IList<IQueryNode> children = node.GetChildren();
+
+ if (children != null && children.Count > 0)
+ {
+
+ for (int i = 0; i < children.Count - 1; i++)
+ {
+ ReadTree(children[i]);
+ }
+
+ ProcessNode(node);
+ ReadTree(children[children.Count - 1]);
+
+ }
+ else
+ {
+ ProcessNode(node);
+ }
+
+ }
+ else
+ {
+ ProcessNode(node);
+ }
+
+ }
+
+ private void ProcessNode(IQueryNode node)
+ {
+
+ if (node is AndQueryNode || node is OrQueryNode)
+ {
+
+ if (!this.latestNodeVerified && this.queryNodeList.Any())
+ {
+ var value = this.queryNodeList[this.queryNodeList.Count - 1];
+ this.queryNodeList.Remove(value);
+
+ this.queryNodeList.Add(ApplyModifier(value, node));
+ this.latestNodeVerified = true;
+
+ }
+
+ }
+ else if (!(node is BooleanQueryNode))
+ {
+ this.queryNodeList.Add(ApplyModifier(node, node.GetParent()));
+ this.latestNodeVerified = false;
+
+ }
+
+ }
+
+
+ public virtual QueryConfigHandler GetQueryConfigHandler()
+ {
+ return this.queryConfig;
+ }
+
+
+ public virtual void SetQueryConfigHandler(QueryConfigHandler queryConfigHandler)
+ {
+ this.queryConfig = queryConfigHandler;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/LowercaseExpandedTermsQueryNodeProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/LowercaseExpandedTermsQueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/LowercaseExpandedTermsQueryNodeProcessor.cs
new file mode 100644
index 0000000..ce22ea0
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/LowercaseExpandedTermsQueryNodeProcessor.cs
@@ -0,0 +1,87 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using Lucene.Net.QueryParsers.Flexible.Core.Processors;
+using Lucene.Net.QueryParsers.Flexible.Core.Util;
+using Lucene.Net.QueryParsers.Flexible.Standard.Config;
+using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
+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.Standard.Processors
+{
+ /// <summary>
+ /// This processor verifies if
+ /// {@link ConfigurationKeys#LOWERCASE_EXPANDED_TERMS} is defined in the
+ /// {@link QueryConfigHandler}. If it is and the expanded terms should be
+ /// lower-cased, it looks for every {@link WildcardQueryNode},
+ /// {@link FuzzyQueryNode} and children of a {@link RangeQueryNode} and lower-case its
+ /// term.
+ /// </summary>
+ /// <seealso cref="ConfigurationKeys#LOWERCASE_EXPANDED_TERMS"/>.
+ public class LowercaseExpandedTermsQueryNodeProcessor : QueryNodeProcessorImpl
+ {
+ public LowercaseExpandedTermsQueryNodeProcessor()
+ {
+ }
+
+
+ public override IQueryNode Process(IQueryNode queryTree)
+ {
+ bool? lowercaseExpandedTerms = GetQueryConfigHandler().Get(ConfigurationKeys.LOWERCASE_EXPANDED_TERMS);
+
+ if (lowercaseExpandedTerms != null && lowercaseExpandedTerms.Value)
+ {
+ return base.Process(queryTree);
+ }
+
+ return queryTree;
+
+ }
+
+
+ protected override IQueryNode PostProcessNode(IQueryNode node)
+ {
+
+ CultureInfo locale = GetQueryConfigHandler().Get(ConfigurationKeys.LOCALE);
+ if (locale == null)
+ {
+ locale = CultureInfo.InvariantCulture; //Locale.getDefault();
+ }
+
+ if (node is WildcardQueryNode
+ || node is FuzzyQueryNode
+ || (node is FieldQueryNode && node.GetParent() is IRangeQueryNode)
+ || node is RegexpQueryNode)
+ {
+
+ ITextableQueryNode txtNode = (ITextableQueryNode)node;
+ ICharSequence text = txtNode.Text;
+ txtNode.Text = text != null ? UnescapedCharSequence.ToLowerCase(text, locale) : null;
+ }
+
+ 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/c83be6be/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/MatchAllDocsQueryNodeProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/MatchAllDocsQueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/MatchAllDocsQueryNodeProcessor.cs
new file mode 100644
index 0000000..4b216ac
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/MatchAllDocsQueryNodeProcessor.cs
@@ -0,0 +1,62 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+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.Standard.Processors
+{
+ /// <summary>
+ /// This processor converts every {@link WildcardQueryNode} that is "*:*" to
+ /// {@link MatchAllDocsQueryNode}.
+ /// </summary>
+ /// <seealso cref="MatchAllDocsQueryNode"/>
+ /// <seealso cref="MatchAllDocsQuery"/>
+ public class MatchAllDocsQueryNodeProcessor : QueryNodeProcessorImpl
+ {
+ public MatchAllDocsQueryNodeProcessor()
+ {
+ // empty constructor
+ }
+
+
+ protected override IQueryNode PostProcessNode(IQueryNode node)
+ {
+
+ if (node is FieldQueryNode)
+ {
+ FieldQueryNode fqn = (FieldQueryNode)node;
+
+ if (fqn.Field.ToString().Equals("*")
+ && fqn.Text.Equals("*"))
+ {
+
+ return new MatchAllDocsQueryNode();
+
+ }
+
+ }
+
+ 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/c83be6be/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/MultiFieldQueryNodeProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/MultiFieldQueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/MultiFieldQueryNodeProcessor.cs
new file mode 100644
index 0000000..1ec617d
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/MultiFieldQueryNodeProcessor.cs
@@ -0,0 +1,130 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using Lucene.Net.QueryParsers.Flexible.Core.Processors;
+using Lucene.Net.QueryParsers.Flexible.Standard.Config;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Standard.Processors
+{
+ /// <summary>
+ /// This processor is used to expand terms so the query looks for the same term
+ /// in different fields. It also boosts a query based on its field.
+ /// <para/>
+ /// This processor looks for every {@link FieldableNode} contained in the query
+ /// node tree. If a {@link FieldableNode} is found, it checks if there is a
+ /// {@link ConfigurationKeys#MULTI_FIELDS} defined in the {@link QueryConfigHandler}. If
+ /// there is, the {@link FieldableNode} is cloned N times and the clones are
+ /// added to a {@link BooleanQueryNode} together with the original node. N is
+ /// defined by the number of fields that it will be expanded to. The
+ /// {@link BooleanQueryNode} is returned.
+ /// </summary>
+ /// <seealso cref="ConfigurationKeys#MULTI_FIELDS"/>
+ public class MultiFieldQueryNodeProcessor : QueryNodeProcessorImpl
+ {
+ private bool processChildren = true;
+
+ public MultiFieldQueryNodeProcessor()
+ {
+ // empty constructor
+ }
+
+
+ protected override IQueryNode PostProcessNode(IQueryNode node)
+ {
+
+ return node;
+
+ }
+
+
+ protected override void ProcessChildren(IQueryNode queryTree)
+ {
+
+ if (this.processChildren)
+ {
+ base.ProcessChildren(queryTree);
+
+ }
+ else
+ {
+ this.processChildren = true;
+ }
+
+ }
+
+ protected override IQueryNode PreProcessNode(IQueryNode node)
+ {
+
+ if (node is IFieldableNode)
+ {
+ this.processChildren = false;
+ IFieldableNode fieldNode = (IFieldableNode)node;
+
+ if (fieldNode.Field == null)
+ {
+ string[] fields = GetQueryConfigHandler().Get(ConfigurationKeys.MULTI_FIELDS);
+
+ if (fields == null)
+ {
+ throw new ArgumentException(
+ "StandardQueryConfigHandler.ConfigurationKeys.MULTI_FIELDS should be set on the QueryConfigHandler");
+ }
+
+ if (fields != null && fields.Length > 0)
+ {
+ fieldNode.Field = fields[0];
+
+ if (fields.Length == 1)
+ {
+ return fieldNode;
+
+ }
+ else
+ {
+ List<IQueryNode> children = new List<IQueryNode>();
+ children.Add(fieldNode);
+
+ for (int i = 1; i < fields.Length; i++)
+ {
+ //try
+ //{
+ fieldNode = (IFieldableNode)fieldNode.CloneTree();
+ fieldNode.Field = fields[i];
+
+ children.Add(fieldNode);
+
+ //}
+ //catch (CloneNotSupportedException e)
+ //{
+ // // should never happen
+ //}
+
+ }
+
+ return new GroupQueryNode(new OrQueryNode(children));
+
+ }
+
+ }
+
+ }
+
+ }
+
+ return node;
+
+ }
+
+
+ protected override IList<IQueryNode> SetChildrenOrder(IList<IQueryNode> children)
+ {
+
+ return children;
+
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/MultiTermRewriteMethodProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/MultiTermRewriteMethodProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/MultiTermRewriteMethodProcessor.cs
new file mode 100644
index 0000000..33e31b5
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/MultiTermRewriteMethodProcessor.cs
@@ -0,0 +1,64 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using Lucene.Net.QueryParsers.Flexible.Core.Processors;
+using Lucene.Net.QueryParsers.Flexible.Standard.Config;
+using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
+using Lucene.Net.Search;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Standard.Processors
+{
+ /// <summary>
+ /// This processor instates the default
+ /// {@link org.apache.lucene.search.MultiTermQuery.RewriteMethod},
+ /// {@link MultiTermQuery#CONSTANT_SCORE_AUTO_REWRITE_DEFAULT}, for multi-term
+ /// query nodes.
+ /// </summary>
+ public class MultiTermRewriteMethodProcessor : QueryNodeProcessorImpl
+ {
+ public static readonly string TAG_ID = "MultiTermRewriteMethodConfiguration";
+
+
+ protected override IQueryNode PostProcessNode(IQueryNode node)
+ {
+
+ // set setMultiTermRewriteMethod for WildcardQueryNode and
+ // PrefixWildcardQueryNode
+ if (node is WildcardQueryNode
+ || node is IAbstractRangeQueryNode || node is RegexpQueryNode)
+ {
+
+ MultiTermQuery.RewriteMethod rewriteMethod = GetQueryConfigHandler().Get(ConfigurationKeys.MULTI_TERM_REWRITE_METHOD);
+
+ if (rewriteMethod == null)
+ {
+ // This should not happen, this configuration is set in the
+ // StandardQueryConfigHandler
+ throw new ArgumentException(
+ "StandardQueryConfigHandler.ConfigurationKeys.MULTI_TERM_REWRITE_METHOD should be set on the QueryConfigHandler");
+ }
+
+ // use a TAG to take the value to the Builder
+ node.SetTag(MultiTermRewriteMethodProcessor.TAG_ID, rewriteMethod);
+
+ }
+
+ 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/c83be6be/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericQueryNodeProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericQueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericQueryNodeProcessor.cs
new file mode 100644
index 0000000..de5a5b4
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericQueryNodeProcessor.cs
@@ -0,0 +1,150 @@
+\ufeffusing Lucene.Net.Documents;
+using Lucene.Net.QueryParsers.Flexible.Core;
+using Lucene.Net.QueryParsers.Flexible.Core.Config;
+using Lucene.Net.QueryParsers.Flexible.Core.Messages;
+using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using Lucene.Net.QueryParsers.Flexible.Core.Processors;
+using Lucene.Net.QueryParsers.Flexible.Messages;
+using Lucene.Net.QueryParsers.Flexible.Standard.Config;
+using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Standard.Processors
+{
+ /// <summary>
+ /// This processor is used to convert {@link FieldQueryNode}s to
+ /// {@link NumericRangeQueryNode}s. It looks for
+ /// {@link ConfigurationKeys#NUMERIC_CONFIG} set in the {@link FieldConfig} of
+ /// every {@link FieldQueryNode} found. If
+ /// {@link ConfigurationKeys#NUMERIC_CONFIG} is found, it considers that
+ /// {@link FieldQueryNode} to be a numeric query and convert it to
+ /// {@link NumericRangeQueryNode} with upper and lower inclusive and lower and
+ /// upper equals to the value represented by the {@link FieldQueryNode} converted
+ /// to {@link Number}. It means that <b>field:1</b> is converted to <b>field:[1
+ /// TO 1]</b>.
+ /// <para/>
+ /// Note that {@link FieldQueryNode}s children of a
+ /// {@link RangeQueryNode} are ignored.
+ /// </summary>
+ /// <seealso cref="ConfigurationKeys#NUMERIC_CONFIG"/>
+ /// <seealso cref="FieldQueryNode"/>
+ /// <seealso cref="NumericConfig"/>
+ /// <seealso cref="NumericQueryNode"/>
+ public class NumericQueryNodeProcessor : QueryNodeProcessorImpl
+ {
+ /**
+ * Constructs a {@link NumericQueryNodeProcessor} object.
+ */
+ public NumericQueryNodeProcessor()
+ {
+ // empty constructor
+ }
+
+
+ protected override IQueryNode PostProcessNode(IQueryNode node)
+ {
+
+ if (node is FieldQueryNode
+ && !(node.GetParent() is IRangeQueryNode))
+ {
+
+ QueryConfigHandler config = GetQueryConfigHandler();
+
+ if (config != null)
+ {
+ FieldQueryNode fieldNode = (FieldQueryNode)node;
+ FieldConfig fieldConfig = config.GetFieldConfig(fieldNode
+ .GetFieldAsString());
+
+ if (fieldConfig != null)
+ {
+ NumericConfig numericConfig = fieldConfig
+ .Get(ConfigurationKeys.NUMERIC_CONFIG);
+
+ if (numericConfig != null)
+ {
+
+ /*NumberFormat*/
+ string numberFormat = numericConfig.GetNumberFormat();
+ string text = fieldNode.GetTextAsString();
+ /*Number*/
+ object number = null;
+
+ if (text.Length > 0)
+ {
+
+ try
+ {
+ //number = numberFormat.parse(text);
+ number = decimal.Parse(text, NumberStyles.Any);// LUCENENET TODO: use the current culture?
+
+ }
+ catch (FormatException e)
+ {
+ throw new QueryNodeParseException(new MessageImpl(
+ QueryParserMessages.COULD_NOT_PARSE_NUMBER, fieldNode
+ .GetTextAsString(), numberFormat.GetType()
+ .AssemblyQualifiedName), e);
+ }
+
+ switch (numericConfig.GetType())
+ {
+ case FieldType.NumericType.LONG:
+ number = Convert.ToInt64(number);
+ break;
+ case FieldType.NumericType.INT:
+ number = Convert.ToInt32(number);
+ break;
+ case FieldType.NumericType.DOUBLE:
+ number = Convert.ToDouble(number);
+ break;
+ case FieldType.NumericType.FLOAT:
+ number = Convert.ToSingle(number);
+ break;
+ }
+
+ }
+ else
+ {
+ throw new QueryNodeParseException(new MessageImpl(
+ QueryParserMessages.NUMERIC_CANNOT_BE_EMPTY, fieldNode.GetFieldAsString()));
+ }
+
+ NumericQueryNode lowerNode = new NumericQueryNode(fieldNode
+ .Field, number, numberFormat);
+ NumericQueryNode upperNode = new NumericQueryNode(fieldNode
+ .Field, number, numberFormat);
+
+ return new NumericRangeQueryNode(lowerNode, upperNode, true, true,
+ numericConfig);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ 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/c83be6be/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericRangeQueryNodeProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericRangeQueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericRangeQueryNodeProcessor.cs
new file mode 100644
index 0000000..f78e218
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/NumericRangeQueryNodeProcessor.cs
@@ -0,0 +1,164 @@
+\ufeffusing Lucene.Net.Documents;
+using Lucene.Net.QueryParsers.Flexible.Core;
+using Lucene.Net.QueryParsers.Flexible.Core.Config;
+using Lucene.Net.QueryParsers.Flexible.Core.Messages;
+using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using Lucene.Net.QueryParsers.Flexible.Core.Processors;
+using Lucene.Net.QueryParsers.Flexible.Core.Util;
+using Lucene.Net.QueryParsers.Flexible.Messages;
+using Lucene.Net.QueryParsers.Flexible.Standard.Config;
+using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Standard.Processors
+{
+ /// <summary>
+ /// This processor is used to convert {@link TermRangeQueryNode}s to
+ /// {@link NumericRangeQueryNode}s. It looks for
+ /// {@link ConfigurationKeys#NUMERIC_CONFIG} set in the {@link FieldConfig} of
+ /// every {@link TermRangeQueryNode} found. If
+ /// {@link ConfigurationKeys#NUMERIC_CONFIG} is found, it considers that
+ /// {@link TermRangeQueryNode} to be a numeric range query and convert it to
+ /// {@link NumericRangeQueryNode}.
+ /// </summary>
+ /// <seealso cref="ConfigurationKeys#NUMERIC_CONFIG"/>
+ /// <seealso cref="TermRangeQueryNode"/>
+ /// <seealso cref="NumericConfig"/>
+ /// <seealso cref="NumericRangeQueryNode"/>
+ public class NumericRangeQueryNodeProcessor : QueryNodeProcessorImpl
+ {
+ /**
+ * Constructs an empty {@link NumericRangeQueryNode} object.
+ */
+ public NumericRangeQueryNodeProcessor()
+ {
+ // empty constructor
+ }
+
+
+ protected override IQueryNode PostProcessNode(IQueryNode node)
+ {
+
+ if (node is TermRangeQueryNode)
+ {
+ QueryConfigHandler config = GetQueryConfigHandler();
+
+ if (config != null)
+ {
+ TermRangeQueryNode termRangeNode = (TermRangeQueryNode)node;
+ FieldConfig fieldConfig = config.GetFieldConfig(StringUtils
+ .ToString(termRangeNode.Field));
+
+ if (fieldConfig != null)
+ {
+
+ NumericConfig numericConfig = fieldConfig
+ .Get(ConfigurationKeys.NUMERIC_CONFIG);
+
+ if (numericConfig != null)
+ {
+
+ FieldQueryNode lower = (FieldQueryNode)termRangeNode.LowerBound;
+ FieldQueryNode upper = (FieldQueryNode)termRangeNode.UpperBound;
+
+ string lowerText = lower.GetTextAsString();
+ string upperText = upper.GetTextAsString();
+ /*NumberFormat*/ string numberFormat = numericConfig.GetNumberFormat();
+ /*Number*/
+ object lowerNumber = null, upperNumber = null;
+
+ if (lowerText.Length > 0)
+ {
+
+ try
+ {
+ //lowerNumber = numberFormat.parse(lowerText);
+ lowerNumber = decimal.Parse(lowerText, NumberStyles.Any);// LUCENENET TODO: use the current culture?
+ }
+ catch (FormatException e)
+ {
+ throw new QueryNodeParseException(new MessageImpl(
+ QueryParserMessages.COULD_NOT_PARSE_NUMBER, lower
+ .GetTextAsString(), numberFormat.GetType()
+ .AssemblyQualifiedName), e);
+ }
+
+ }
+
+ if (upperText.Length > 0)
+ {
+
+ try
+ {
+ //upperNumber = numberFormat.parse(upperText);
+ upperNumber = decimal.Parse(upperText, NumberStyles.Any);// LUCENENET TODO: use the current culture?
+ }
+ catch (FormatException e)
+ {
+ throw new QueryNodeParseException(new MessageImpl(
+ QueryParserMessages.COULD_NOT_PARSE_NUMBER, upper
+ .GetTextAsString(), numberFormat.GetType()
+ .AssemblyQualifiedName), e);
+ }
+
+ }
+
+ switch (numericConfig.GetType())
+ {
+ case FieldType.NumericType.LONG:
+ if (upperNumber != null) upperNumber = Convert.ToInt64(upperNumber);
+ if (lowerNumber != null) lowerNumber = Convert.ToInt64(lowerNumber);
+ break;
+ case FieldType.NumericType.INT:
+ if (upperNumber != null) upperNumber = Convert.ToInt32(upperNumber);
+ if (lowerNumber != null) lowerNumber = Convert.ToInt32(lowerNumber);
+ break;
+ case FieldType.NumericType.DOUBLE:
+ if (upperNumber != null) upperNumber = Convert.ToDouble(upperNumber);
+ if (lowerNumber != null) lowerNumber = Convert.ToDouble(lowerNumber);
+ break;
+ case FieldType.NumericType.FLOAT:
+ if (upperNumber != null) upperNumber = Convert.ToSingle(upperNumber);
+ if (lowerNumber != null) lowerNumber = Convert.ToSingle(lowerNumber);
+ break;
+ }
+
+ NumericQueryNode lowerNode = new NumericQueryNode(
+ termRangeNode.Field, lowerNumber, numberFormat);
+ NumericQueryNode upperNode = new NumericQueryNode(
+ termRangeNode.Field, upperNumber, numberFormat);
+
+ bool lowerInclusive = termRangeNode.IsLowerInclusive;
+ bool upperInclusive = termRangeNode.IsUpperInclusive;
+
+ return new NumericRangeQueryNode(lowerNode, upperNode,
+ lowerInclusive, upperInclusive, numericConfig);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ 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/c83be6be/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/OpenRangeQueryNodeProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/OpenRangeQueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/OpenRangeQueryNodeProcessor.cs
new file mode 100644
index 0000000..9fbf008
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/OpenRangeQueryNodeProcessor.cs
@@ -0,0 +1,69 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using Lucene.Net.QueryParsers.Flexible.Core.Processors;
+using Lucene.Net.QueryParsers.Flexible.Core.Util;
+using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
+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.Standard.Processors
+{
+ /// <summary>
+ /// Processes {@link TermRangeQuery}s with open ranges.
+ /// </summary>
+ public class OpenRangeQueryNodeProcessor : QueryNodeProcessorImpl
+ {
+ public readonly static string OPEN_RANGE_TOKEN = "*";
+
+ public OpenRangeQueryNodeProcessor() { }
+
+
+ protected override IQueryNode PostProcessNode(IQueryNode node)
+ {
+
+ if (node is TermRangeQueryNode)
+ {
+ TermRangeQueryNode rangeNode = (TermRangeQueryNode)node;
+ FieldQueryNode lowerNode = (FieldQueryNode)rangeNode.LowerBound;
+ FieldQueryNode upperNode = (FieldQueryNode)rangeNode.UpperBound;
+ ICharSequence lowerText = lowerNode.Text;
+ ICharSequence upperText = upperNode.Text;
+
+ if (OPEN_RANGE_TOKEN.Equals(upperNode.GetTextAsString())
+ && (!(upperText is UnescapedCharSequence) || !((UnescapedCharSequence)upperText)
+ .WasEscaped(0)))
+ {
+ upperText = "".ToCharSequence();
+ }
+
+ if (OPEN_RANGE_TOKEN.Equals(lowerNode.GetTextAsString())
+ && (!(lowerText is UnescapedCharSequence) || !((UnescapedCharSequence)lowerText)
+ .WasEscaped(0)))
+ {
+ lowerText = "".ToCharSequence();
+ }
+
+ lowerNode.Text = lowerText;
+ upperNode.Text = upperText;
+ }
+
+ 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/c83be6be/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/PhraseSlopQueryNodeProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/PhraseSlopQueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/PhraseSlopQueryNodeProcessor.cs
new file mode 100644
index 0000000..9755442
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/PhraseSlopQueryNodeProcessor.cs
@@ -0,0 +1,61 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using Lucene.Net.QueryParsers.Flexible.Core.Processors;
+using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Standard.Processors
+{
+ /// <summary>
+ /// This processor removes invalid {@link SlopQueryNode} objects in the query
+ /// node tree. A {@link SlopQueryNode} is invalid if its child is neither a
+ /// {@link TokenizedPhraseQueryNode} nor a {@link MultiPhraseQueryNode}.
+ /// </summary>
+ /// <seealso cref="SlopQueryNode"/>
+ public class PhraseSlopQueryNodeProcessor : QueryNodeProcessorImpl
+ {
+ public PhraseSlopQueryNodeProcessor()
+ {
+ // empty constructor
+ }
+
+
+ protected override IQueryNode PostProcessNode(IQueryNode node)
+ {
+
+ if (node is SlopQueryNode)
+ {
+ SlopQueryNode phraseSlopNode = (SlopQueryNode)node;
+
+ if (!(phraseSlopNode.GetChild() is TokenizedPhraseQueryNode)
+ && !(phraseSlopNode.GetChild() is MultiPhraseQueryNode))
+ {
+ return phraseSlopNode.GetChild();
+ }
+
+ }
+
+ 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/c83be6be/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/RemoveEmptyNonLeafQueryNodeProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/RemoveEmptyNonLeafQueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/RemoveEmptyNonLeafQueryNodeProcessor.cs
new file mode 100644
index 0000000..896f749
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/RemoveEmptyNonLeafQueryNodeProcessor.cs
@@ -0,0 +1,110 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using Lucene.Net.QueryParsers.Flexible.Core.Processors;
+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.Standard.Processors
+{
+ /// <summary>
+ /// This processor removes every {@link QueryNode} that is not a leaf and has not
+ /// children. If after processing the entire tree the root node is not a leaf and
+ /// has no children, a {@link MatchNoDocsQueryNode} object is returned.
+ /// <para/>
+ /// This processor is used at the end of a pipeline to avoid invalid query node
+ /// tree structures like a {@link GroupQueryNode} or {@link ModifierQueryNode}
+ /// with no children.
+ /// </summary>
+ /// <seealso cref="QueryNode"/>
+ /// <seealso cref="MatchNoDocsQueryNode"/>
+ public class RemoveEmptyNonLeafQueryNodeProcessor : QueryNodeProcessorImpl
+ {
+ private List<IQueryNode> childrenBuffer = new List<IQueryNode>();
+
+ public RemoveEmptyNonLeafQueryNodeProcessor()
+ {
+ // empty constructor
+ }
+
+
+ public override IQueryNode Process(IQueryNode queryTree)
+ {
+ queryTree = base.Process(queryTree);
+
+ if (!queryTree.IsLeaf())
+ {
+
+ IList<IQueryNode> children = queryTree.GetChildren();
+
+ if (children == null || children.Count == 0)
+ {
+ return new MatchNoDocsQueryNode();
+ }
+
+ }
+
+ return queryTree;
+
+ }
+
+
+ protected override IQueryNode PostProcessNode(IQueryNode node)
+ {
+
+ return node;
+
+ }
+
+
+ protected override IQueryNode PreProcessNode(IQueryNode node)
+ {
+
+ return node;
+
+ }
+
+
+ protected override IList<IQueryNode> SetChildrenOrder(IList<IQueryNode> children)
+ {
+
+ try
+ {
+
+ foreach (IQueryNode child in children)
+ {
+
+ if (!child.IsLeaf())
+ {
+
+ IList<IQueryNode> grandChildren = child.GetChildren();
+
+ if (grandChildren != null && grandChildren.Count > 0)
+ {
+ this.childrenBuffer.Add(child);
+ }
+
+ }
+ else
+ {
+ this.childrenBuffer.Add(child);
+ }
+
+ }
+
+ children.Clear();
+ children.AddRange(this.childrenBuffer);
+
+ }
+ finally
+ {
+ this.childrenBuffer.Clear();
+ }
+
+ return children;
+
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/StandardQueryNodeProcessorPipeline.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/StandardQueryNodeProcessorPipeline.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/StandardQueryNodeProcessorPipeline.cs
new file mode 100644
index 0000000..35b4491
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/StandardQueryNodeProcessorPipeline.cs
@@ -0,0 +1,54 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Config;
+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.Standard.Processors
+{
+ /// <summary>
+ /// This pipeline has all the processors needed to process a query node tree,
+ /// generated by {@link StandardSyntaxParser}, already assembled.
+ /// <para/>
+ /// The order they are assembled affects the results.
+ /// <para/>
+ /// This processor pipeline was designed to work with
+ /// {@link StandardQueryConfigHandler}.
+ /// <para/>
+ /// The result query node tree can be used to build a {@link Query} object using
+ /// {@link StandardQueryTreeBuilder}.
+ /// </summary>
+ /// <seealso cref="StandardQueryTreeBuilder"/>
+ /// <seealso cref="StandardQueryConfigHandler"/>
+ /// <seealso cref="StandardSyntaxParser"/>
+ public class StandardQueryNodeProcessorPipeline : QueryNodeProcessorPipeline
+ {
+ public StandardQueryNodeProcessorPipeline(QueryConfigHandler queryConfig)
+ : base(queryConfig)
+ {
+ Add(new WildcardQueryNodeProcessor());
+ Add(new MultiFieldQueryNodeProcessor());
+ Add(new FuzzyQueryNodeProcessor());
+ Add(new MatchAllDocsQueryNodeProcessor());
+ Add(new OpenRangeQueryNodeProcessor());
+ Add(new NumericQueryNodeProcessor());
+ Add(new NumericRangeQueryNodeProcessor());
+ Add(new LowercaseExpandedTermsQueryNodeProcessor());
+ Add(new TermRangeQueryNodeProcessor());
+ Add(new AllowLeadingWildcardProcessor());
+ Add(new AnalyzerQueryNodeProcessor());
+ Add(new PhraseSlopQueryNodeProcessor());
+ //add(new GroupQueryNodeProcessor());
+ Add(new BooleanQuery2ModifierNodeProcessor());
+ Add(new NoChildOptimizationQueryNodeProcessor());
+ Add(new RemoveDeletedQueryNodesProcessor());
+ Add(new RemoveEmptyNonLeafQueryNodeProcessor());
+ Add(new BooleanSingleChildOptimizationQueryNodeProcessor());
+ Add(new DefaultPhraseSlopQueryNodeProcessor());
+ Add(new BoostQueryNodeProcessor());
+ Add(new MultiTermRewriteMethodProcessor());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/TermRangeQueryNodeProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/TermRangeQueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/TermRangeQueryNodeProcessor.cs
new file mode 100644
index 0000000..6ddbd75
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/TermRangeQueryNodeProcessor.cs
@@ -0,0 +1,164 @@
+\ufeffusing Lucene.Net.Documents;
+using Lucene.Net.QueryParsers.Flexible.Core.Config;
+using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using Lucene.Net.QueryParsers.Flexible.Core.Processors;
+using Lucene.Net.QueryParsers.Flexible.Standard.Config;
+using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
+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.Standard.Processors
+{
+ /// <summary>
+ /// This processors process {@link TermRangeQueryNode}s. It reads the lower and
+ /// upper bounds value from the {@link TermRangeQueryNode} object and try
+ /// to parse their values using a {@link DateFormat}. If the values cannot be
+ /// parsed to a date value, it will only create the {@link TermRangeQueryNode}
+ /// using the non-parsed values.
+ /// <para/>
+ /// If a {@link ConfigurationKeys#LOCALE} is defined in the
+ /// {@link QueryConfigHandler} it will be used to parse the date, otherwise
+ /// {@link Locale#getDefault()} will be used.
+ /// <para/>
+ /// If a {@link ConfigurationKeys#DATE_RESOLUTION} is defined and the
+ /// {@link Resolution} is not <code>null</code> it will also be used to parse the
+ /// date value.
+ /// </summary>
+ /// <seealso cref="ConfigurationKeys#DATE_RESOLUTION"/>
+ /// <seealso cref="ConfigurationKeys#LOCALE"/>
+ /// <seealso cref="TermRangeQueryNode"/>
+ public class TermRangeQueryNodeProcessor : QueryNodeProcessorImpl
+ {
+ public TermRangeQueryNodeProcessor()
+ {
+ // empty constructor
+ }
+
+
+ protected override IQueryNode PostProcessNode(IQueryNode node)
+ {
+
+ if (node is TermRangeQueryNode)
+ {
+ TermRangeQueryNode termRangeNode = (TermRangeQueryNode)node;
+ FieldQueryNode upper = (FieldQueryNode)termRangeNode.UpperBound;
+ FieldQueryNode lower = (FieldQueryNode)termRangeNode.LowerBound;
+
+ // LUCENENET TODO: Add a NOT_SET value so we have a logical default?
+ DateTools.Resolution dateRes = DateTools.Resolution.MINUTE/* = null*/;
+ bool inclusive = false;
+ CultureInfo locale = GetQueryConfigHandler().Get(ConfigurationKeys.LOCALE);
+
+ if (locale == null)
+ {
+ locale = CultureInfo.CurrentCulture; //Locale.getDefault();
+ }
+
+ TimeZoneInfo timeZone = GetQueryConfigHandler().Get(ConfigurationKeys.TIMEZONE);
+
+ if (timeZone == null)
+ {
+ timeZone = TimeZoneInfo.Local; //TimeZone.getDefault();
+ }
+
+ string field = termRangeNode.Field;
+ string fieldStr = null;
+
+ if (field != null)
+ {
+ fieldStr = field.ToString();
+ }
+
+ FieldConfig fieldConfig = GetQueryConfigHandler()
+ .GetFieldConfig(fieldStr);
+
+ if (fieldConfig != null)
+ {
+ dateRes = fieldConfig.Get(ConfigurationKeys.DATE_RESOLUTION);
+ }
+
+ if (termRangeNode.IsUpperInclusive)
+ {
+ inclusive = true;
+ }
+
+ string part1 = lower.GetTextAsString();
+ string part2 = upper.GetTextAsString();
+
+ try
+ {
+ //DateFormat df = DateFormat.GetDateInstance(DateFormat.SHORT, locale);
+ //df.setLenient(true);
+
+ if (part1.Length > 0)
+ {
+ //DateTime d1 = df.parse(part1);
+ DateTime d1 = DateTime.Parse(part1, locale);
+ part1 = DateTools.DateToString(d1, dateRes);
+ lower.Text = new StringCharSequenceWrapper(part1);
+ }
+
+ if (part2.Length > 0)
+ {
+ //DateTime d2 = df.parse(part2);
+ DateTime d2 = DateTime.Parse(part2, locale);
+ if (inclusive)
+ {
+ // The user can only specify the date, not the time, so make sure
+ // the time is set to the latest possible time of that date to
+ // really
+ // include all documents:
+ //Calendar cal = Calendar.getInstance(timeZone, locale);
+ //cal.setTime(d2);
+ //cal.set(Calendar.HOUR_OF_DAY, 23);
+ //cal.set(Calendar.MINUTE, 59);
+ //cal.set(Calendar.SECOND, 59);
+ //cal.set(Calendar.MILLISECOND, 999);
+ //d2 = cal.getTime();
+
+ var cal = locale.Calendar;
+ d2 = cal.AddHours(d2, 23);
+ d2 = cal.AddMinutes(d2, 59);
+ d2 = cal.AddSeconds(d2, 59);
+ d2 = cal.AddMilliseconds(d2, 999);
+ }
+
+ part2 = DateTools.DateToString(d2, dateRes);
+ upper.Text = new StringCharSequenceWrapper(part2);
+
+ }
+
+ }
+ catch (Exception e)
+ {
+ // do nothing
+ }
+
+ }
+
+ 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/c83be6be/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/WildcardQueryNodeProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/WildcardQueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/WildcardQueryNodeProcessor.cs
new file mode 100644
index 0000000..b38f60b
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/Processors/WildcardQueryNodeProcessor.cs
@@ -0,0 +1,131 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using Lucene.Net.QueryParsers.Flexible.Core.Processors;
+using Lucene.Net.QueryParsers.Flexible.Core.Util;
+using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
+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.Standard.Processors
+{
+ /// <summary>
+ /// The {@link StandardSyntaxParser} creates {@link PrefixWildcardQueryNode} nodes which
+ /// have values containing the prefixed wildcard. However, Lucene
+ /// {@link PrefixQuery} cannot contain the prefixed wildcard. So, this processor
+ /// basically removed the prefixed wildcard from the
+ /// {@link PrefixWildcardQueryNode} value.
+ /// </summary>
+ /// <seealso cref="PrefixQuery"/>
+ /// <seealso cref="PrefixWildcardQueryNode"/>
+ public class WildcardQueryNodeProcessor : QueryNodeProcessorImpl
+ {
+ public WildcardQueryNodeProcessor()
+ {
+ // empty constructor
+ }
+
+
+ protected override IQueryNode PostProcessNode(IQueryNode node)
+ {
+
+ // the old Lucene Parser ignores FuzzyQueryNode that are also PrefixWildcardQueryNode or WildcardQueryNode
+ // we do the same here, also ignore empty terms
+ if (node is FieldQueryNode || node is FuzzyQueryNode)
+ {
+ FieldQueryNode fqn = (FieldQueryNode)node;
+ string text = fqn.Text.ToString();
+
+ // do not process wildcards for TermRangeQueryNode children and
+ // QuotedFieldQueryNode to reproduce the old parser behavior
+ if (fqn.GetParent() is TermRangeQueryNode
+ || fqn is QuotedFieldQueryNode
+ || text.Length <= 0)
+ {
+ // Ignore empty terms
+ return node;
+ }
+
+ // Code below simulates the old lucene parser behavior for wildcards
+
+ if (IsPrefixWildcard(text))
+ {
+ PrefixWildcardQueryNode prefixWildcardQN = new PrefixWildcardQueryNode(fqn);
+ return prefixWildcardQN;
+
+ }
+ else if (IsWildcard(text))
+ {
+ WildcardQueryNode wildcardQN = new WildcardQueryNode(fqn);
+ return wildcardQN;
+ }
+
+ }
+
+ return node;
+
+ }
+
+ private bool IsWildcard(string text)
+ {
+ if (text == null || text.Length <= 0) return false;
+
+ // If a un-escaped '*' or '?' if found return true
+ // start at the end since it's more common to put wildcards at the end
+ for (int i = text.Length - 1; i >= 0; i--)
+ {
+ if ((text[i] == '*' || text[i] == '?') && !UnescapedCharSequence.WasEscaped(new StringCharSequenceWrapper(text), i))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private bool IsPrefixWildcard(string text)
+ {
+ if (text == null || text.Length <= 0 || !IsWildcard(text)) return false;
+
+ // Validate last character is a '*' and was not escaped
+ // If single '*' is is a wildcard not prefix to simulate old queryparser
+ if (text[text.Length - 1] != '*') return false;
+ if (UnescapedCharSequence.WasEscaped(new StringCharSequenceWrapper(text), text.Length - 1)) return false;
+ if (text.Length == 1) return false;
+
+ // Only make a prefix if there is only one single star at the end and no '?' or '*' characters
+ // If single wildcard return false to mimic old queryparser
+ for (int i = 0; i < text.Length; i++)
+ {
+ if (text[i] == '?') return false;
+ if (text[i] == '*' && !UnescapedCharSequence.WasEscaped(new StringCharSequenceWrapper(text), i))
+ {
+ if (i == text.Length - 1)
+ return true;
+ else
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+
+ 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/c83be6be/src/Lucene.Net.QueryParser/Flexible/Standard/QueryParserUtil.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Standard/QueryParserUtil.cs b/src/Lucene.Net.QueryParser/Flexible/Standard/QueryParserUtil.cs
new file mode 100644
index 0000000..55eb099
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Standard/QueryParserUtil.cs
@@ -0,0 +1,202 @@
+\ufeffusing Lucene.Net.Analysis;
+using Lucene.Net.Search;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Standard
+{
+ /// <summary>
+ /// This class defines utility methods to (help) parse query strings into
+ /// {@link Query} objects.
+ /// </summary>
+ public sealed class QueryParserUtil
+ {
+ /**
+ * Parses a query which searches on the fields specified.
+ * <p>
+ * If x fields are specified, this effectively constructs:
+ *
+ * <pre>
+ * <code>
+ * (field1:query1) (field2:query2) (field3:query3)...(fieldx:queryx)
+ * </code>
+ * </pre>
+ *
+ * @param queries
+ * Queries strings to parse
+ * @param fields
+ * Fields to search on
+ * @param analyzer
+ * Analyzer to use
+ * @throws IllegalArgumentException
+ * if the length of the queries array differs from the length of the
+ * fields array
+ */
+ public static Query Parse(string[] queries, string[] fields, Analyzer analyzer)
+ {
+ if (queries.Length != fields.Length)
+ throw new ArgumentException("queries.length != fields.length");
+ BooleanQuery bQuery = new BooleanQuery();
+
+ StandardQueryParser qp = new StandardQueryParser();
+ qp.Analyzer = analyzer;
+
+ for (int i = 0; i < fields.Length; i++)
+ {
+ Query q = qp.Parse(queries[i], fields[i]) as Query;
+
+ if (q != null && // q never null, just being defensive
+ (!(q is BooleanQuery) || ((BooleanQuery)q).GetClauses().Count > 0))
+ {
+ bQuery.Add(q, BooleanClause.Occur.SHOULD);
+ }
+ }
+ return bQuery;
+ }
+
+ /**
+ * Parses a query, searching on the fields specified. Use this if you need to
+ * specify certain fields as required, and others as prohibited.
+ * <p>
+ *
+ * Usage:
+ * <pre class="prettyprint">
+ * <code>
+ * String[] fields = {"filename", "contents", "description"};
+ * BooleanClause.Occur[] flags = {BooleanClause.Occur.SHOULD,
+ * BooleanClause.Occur.MUST,
+ * BooleanClause.Occur.MUST_NOT};
+ * MultiFieldQueryParser.parse("query", fields, flags, analyzer);
+ * </code>
+ * </pre>
+ *<p>
+ * The code above would construct a query:
+ *
+ * <pre>
+ * <code>
+ * (filename:query) +(contents:query) -(description:query)
+ * </code>
+ * </pre>
+ *
+ * @param query
+ * Query string to parse
+ * @param fields
+ * Fields to search on
+ * @param flags
+ * Flags describing the fields
+ * @param analyzer
+ * Analyzer to use
+ * @throws IllegalArgumentException
+ * if the length of the fields array differs from the length of the
+ * flags array
+ */
+ public static Query Parse(string query, string[] fields,
+ BooleanClause.Occur[] flags, Analyzer analyzer)
+ {
+ if (fields.Length != flags.Length)
+ throw new ArgumentException("fields.length != flags.length");
+ BooleanQuery bQuery = new BooleanQuery();
+
+ StandardQueryParser qp = new StandardQueryParser();
+ qp.Analyzer = analyzer;
+
+ for (int i = 0; i < fields.Length; i++)
+ {
+ Query q = qp.Parse(query, fields[i]) as Query;
+
+ if (q != null && // q never null, just being defensive
+ (!(q is BooleanQuery) || ((BooleanQuery)q).GetClauses().Count > 0))
+ {
+ bQuery.Add(q, flags[i]);
+ }
+ }
+ return bQuery;
+ }
+
+ /**
+ * Parses a query, searching on the fields specified. Use this if you need to
+ * specify certain fields as required, and others as prohibited.
+ * <p>
+ *
+ * Usage:
+ * <pre class="prettyprint">
+ * <code>
+ * String[] query = {"query1", "query2", "query3"};
+ * String[] fields = {"filename", "contents", "description"};
+ * BooleanClause.Occur[] flags = {BooleanClause.Occur.SHOULD,
+ * BooleanClause.Occur.MUST,
+ * BooleanClause.Occur.MUST_NOT};
+ * MultiFieldQueryParser.parse(query, fields, flags, analyzer);
+ * </code>
+ * </pre>
+ *<p>
+ * The code above would construct a query:
+ *
+ * <pre>
+ * <code>
+ * (filename:query1) +(contents:query2) -(description:query3)
+ * </code>
+ * </pre>
+ *
+ * @param queries
+ * Queries string to parse
+ * @param fields
+ * Fields to search on
+ * @param flags
+ * Flags describing the fields
+ * @param analyzer
+ * Analyzer to use
+ * @throws IllegalArgumentException
+ * if the length of the queries, fields, and flags array differ
+ */
+ public static Query Parse(string[] queries, string[] fields,
+ BooleanClause.Occur[] flags, Analyzer analyzer)
+ {
+ if (!(queries.Length == fields.Length && queries.Length == flags.Length))
+ throw new ArgumentException(
+ "queries, fields, and flags array have have different length");
+ BooleanQuery bQuery = new BooleanQuery();
+
+ StandardQueryParser qp = new StandardQueryParser();
+ qp.Analyzer = analyzer;
+
+ for (int i = 0; i < fields.Length; i++)
+ {
+ Query q = qp.Parse(queries[i], fields[i]) as Query;
+
+ if (q != null && // q never null, just being defensive
+ (!(q is BooleanQuery) || ((BooleanQuery)q).GetClauses().Count > 0))
+ {
+ bQuery.Add(q, flags[i]);
+ }
+ }
+ return bQuery;
+ }
+
+ /**
+ * Returns a String where those characters that TextParser expects to be
+ * escaped are escaped by a preceding <code>\</code>.
+ */
+ public static string Escape(string s)
+ {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < s.Length; i++)
+ {
+ char c = s[i];
+ // These characters are part of the query syntax and must be escaped
+ if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '(' || c == ')'
+ || c == ':' || c == '^' || c == '[' || c == ']' || c == '\"'
+ || c == '{' || c == '}' || c == '~' || c == '*' || c == '?'
+ || c == '|' || c == '&' || c == '/')
+ {
+ sb.Append('\\');
+ }
+ sb.Append(c);
+ }
+ return sb.ToString();
+ }
+ }
+}