예제 #1
0
        public void TestAntiM()
        {
            _searcher = new IndexSearcher(_directory, true);

            const double miles = 6.0;

            Console.WriteLine("testAntiM");
            // create a distance query
            var dq = new DistanceQueryBuilder(_lat, _lng, miles, LatField, LngField, CartesianTierPlotter.DefaltFieldPrefix, true);

            Console.WriteLine(dq);
            //create a term query to search against all documents
            Query tq = new TermQuery(new Term("metafile", "doc"));

            var  dsort = new DistanceFieldComparatorSource(dq.DistanceFilter);
            Sort sort  = new Sort(new SortField("foo", dsort, false));

            // Perform the search, using the term query, the distance filter, and the
            // distance sort
            TopDocs hits    = _searcher.Search(tq, dq.Filter, 1000, sort);
            int     results = hits.totalHits;

            ScoreDoc[] scoreDocs = hits.scoreDocs;

            // Get a list of distances
            Dictionary <int, Double> distances = dq.DistanceFilter.Distances;


            Console.WriteLine("Distance Filter filtered: " + distances.Count);
            Console.WriteLine("Results: " + results);
            Console.WriteLine("=============================");
            Console.WriteLine("Distances should be 7 " + distances.Count);
            Console.WriteLine("Results should be 7 " + results);

            Assert.AreEqual(7, distances.Count);             // fixed a store of only needed distances
            Assert.AreEqual(7, results);

            double lastDistance = 0;

            for (int i = 0; i < results; i++)
            {
                Document d = _searcher.Doc(scoreDocs[i].doc);

                String name         = d.Get("name");
                double rsLat        = NumericUtils.PrefixCodedToDouble(d.Get(LatField));
                double rsLng        = NumericUtils.PrefixCodedToDouble(d.Get(LngField));
                Double geo_distance = distances[scoreDocs[i].doc];

                double distance = DistanceUtils.GetInstance().GetDistanceMi(_lat, _lng, rsLat, rsLng);
                double llm      = DistanceUtils.GetInstance().GetLLMDistance(_lat, _lng, rsLat, rsLng);

                Console.WriteLine("Name: " + name + ", Distance " + distance);

                Assert.IsTrue(Math.Abs((distance - llm)) < 1);
                Assert.IsTrue((distance < miles));
                Assert.IsTrue(geo_distance >= lastDistance);

                lastDistance = geo_distance;
            }
        }
예제 #2
0
        public IEnumerable <Service> Execute(ISession session)
        {
            var serviceType   = typeof(Service);
            var dq            = new DistanceQueryBuilder(_userLocation.Y, _userLocation.X, _distance * MeterInMiles, "Location_Latitude", "Location_Longitude", CartesianTierPlotter.DefaltFieldPrefix, false);
            var metaTermQuery = new TermQuery(new Term("metafile", "doc"));

            var  dsort = new DistanceFieldComparatorSource(dq.DistanceFilter);
            Sort sort  = new Sort(new SortField("Location", dsort, false));

            var booleanQuery = new BooleanQuery();

            booleanQuery.Add(metaTermQuery, BooleanClause.Occur.SHOULD);

            if (!string.IsNullOrWhiteSpace(_searchModel.Terms))
            {
                var analyzer    = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29);
                var queryParser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_29, new[] { "Title", "Body", "Category_Name" }, analyzer);
                var termQuery   = queryParser.Parse(_searchModel.Terms);

                booleanQuery.Add(termQuery, BooleanClause.Occur.MUST);
            }

            if (_searchModel.CategoryId != null)
            {
                var categoryQuery = new TermQuery(new Term("Category_Id", _searchModel.CategoryId.Value.ToString()));
                booleanQuery.Add(categoryQuery, BooleanClause.Occur.MUST);
            }

            if (_searchModel.Type != null)
            {
                if (_searchModel.Type.Value == (byte)ServiceType.Offering)
                {
                    serviceType = typeof(ServiceOffering);
                }
                else if (_searchModel.Type.Value == (byte)ServiceType.Request)
                {
                    serviceType = typeof(ServiceRequest);
                }
            }

            return(session.FullTextSession().CreateFullTextQuery(booleanQuery, serviceType)
                   .SetFilter(dq.Filter).SetFetchSize(PageSize).List <Service>());
        }
        /// <summary>
        /// Perform a Look search
        /// </summary>
        /// <param name="lookQuery">A LookQuery model for the search criteria</param>
        /// <returns>A LookResult model for the search response</returns>
        public static LookResult RunQuery(LookQuery lookQuery)
        {
            // flag to indicate whether there are any query clauses in the supplied LookQuery
            bool hasQuery = lookQuery?.Compiled != null ? true : false;

            if (lookQuery == null)
            {
                return(new LookResult("LookQuery object was null"));
            }

            if (lookQuery.SearchingContext == null) // supplied by unit test to skip examine dependency
            {
                // attempt to get searching context from examine searcher name
                lookQuery.SearchingContext = LookService.GetSearchingContext(lookQuery.SearcherName);

                if (lookQuery.SearchingContext == null)
                {
                    return(new LookResult("SearchingContext was null"));
                }
            }

            if (lookQuery.Compiled == null)
            {
                BooleanQuery query  = null; // the lucene query being built
                Filter       filter = null; // used for geospatial queries
                Sort         sort   = null;
                Func <string, IHtmlString> getHighlight = x => null;
                Func <int, double?>        getDistance  = x => null;

                query = new BooleanQuery();

                #region RawQuery

                if (!string.IsNullOrWhiteSpace(lookQuery.RawQuery))
                {
                    hasQuery = true;

                    query.Add(
                        new QueryParser(Lucene.Net.Util.Version.LUCENE_29, null, lookQuery.SearchingContext.Analyzer).Parse(lookQuery.RawQuery),
                        BooleanClause.Occur.MUST);
                }

                #endregion

                #region ExamineQuery

                if (lookQuery.ExamineQuery != null)
                {
                    var luceneSearchCriteria = lookQuery.ExamineQuery as LuceneSearchCriteria;

                    if (luceneSearchCriteria.Query != null)
                    {
                        hasQuery = true;

                        query.Add(luceneSearchCriteria.Query, BooleanClause.Occur.MUST);
                    }
                }

                #endregion

                #region NodeQuery

                if (lookQuery.NodeQuery != null)
                {
                    hasQuery = true;

                    query.Add(new TermQuery(new Term(LookConstants.HasNodeField, "1")), BooleanClause.Occur.MUST);

                    if (lookQuery.NodeQuery.Types != null && lookQuery.NodeQuery.Types.Any())
                    {
                        var nodeTypeQuery = new BooleanQuery();

                        foreach (var nodeType in lookQuery.NodeQuery.Types)
                        {
                            nodeTypeQuery.Add(
                                new TermQuery(
                                    new Term(LookConstants.NodeTypeField, nodeType.ToString())),
                                BooleanClause.Occur.SHOULD);
                        }

                        query.Add(nodeTypeQuery, BooleanClause.Occur.MUST);
                    }

                    switch (lookQuery.NodeQuery.DetachedQuery)
                    {
                    case DetachedQuery.ExcludeDetached:

                        query.Add(
                            new TermQuery(new Term(LookConstants.IsDetachedField, "1")),
                            BooleanClause.Occur.MUST_NOT);

                        break;

                    case DetachedQuery.OnlyDetached:

                        query.Add(
                            new TermQuery(new Term(LookConstants.IsDetachedField, "1")),
                            BooleanClause.Occur.MUST);

                        break;
                    }

                    if (lookQuery.NodeQuery.Cultures != null && lookQuery.NodeQuery.Cultures.Any())
                    {
                        var nodeCultureQuery = new BooleanQuery();

                        foreach (var nodeCulture in lookQuery.NodeQuery.Cultures)
                        {
                            nodeCultureQuery.Add(
                                new TermQuery(
                                    new Term(LookConstants.CultureField, nodeCulture.LCID.ToString())),
                                BooleanClause.Occur.SHOULD);
                        }

                        query.Add(nodeCultureQuery, BooleanClause.Occur.MUST);
                    }

                    if (lookQuery.NodeQuery.Aliases != null && lookQuery.NodeQuery.Aliases.Any())
                    {
                        var nodeAliasQuery = new BooleanQuery();

                        foreach (var typeAlias in lookQuery.NodeQuery.Aliases)
                        {
                            nodeAliasQuery.Add(
                                new TermQuery(new Term(LookConstants.NodeAliasField, typeAlias.ToLower())),
                                BooleanClause.Occur.SHOULD);
                        }

                        query.Add(nodeAliasQuery, BooleanClause.Occur.MUST);
                    }

                    if (lookQuery.NodeQuery.NotIds != null && lookQuery.NodeQuery.NotIds.Any())
                    {
                        foreach (var exculudeId in lookQuery.NodeQuery.NotIds)
                        {
                            query.Add(
                                new TermQuery(new Term(LookConstants.NodeIdField, exculudeId.ToString())),
                                BooleanClause.Occur.MUST_NOT);
                        }
                    }

                    if (lookQuery.NodeQuery.NotKeys != null && lookQuery.NodeQuery.NotKeys.Any())
                    {
                        foreach (var excludeKey in lookQuery.NodeQuery.NotKeys)
                        {
                            query.Add(
                                new TermQuery(new Term(LookConstants.NodeKeyField, excludeKey)),
                                BooleanClause.Occur.MUST_NOT);
                        }
                    }
                }

                #endregion

                #region NameQuery

                if (lookQuery.NameQuery != null)
                {
                    hasQuery = true;

                    query.Add(new TermQuery(new Term(LookConstants.HasNameField, "1")), BooleanClause.Occur.MUST);

                    string wildcard1 = null;
                    string wildcard2 = null; // incase Contains specified with StartsWith and/or EndsWith

                    if (!string.IsNullOrEmpty(lookQuery.NameQuery.StartsWith))
                    {
                        if (!string.IsNullOrEmpty(lookQuery.NameQuery.Is))
                        {
                            if (!lookQuery.NameQuery.Is.StartsWith(lookQuery.NameQuery.StartsWith))
                            {
                                return(new LookResult("Conflict in NameQuery between Is and StartsWith"));
                            }
                        }
                        else
                        {
                            wildcard1 = lookQuery.NameQuery.StartsWith + "*";
                        }
                    }

                    if (!string.IsNullOrEmpty(lookQuery.NameQuery.EndsWith))
                    {
                        if (!string.IsNullOrEmpty(lookQuery.NameQuery.Is))
                        {
                            if (!lookQuery.NameQuery.Is.EndsWith(lookQuery.NameQuery.EndsWith))
                            {
                                return(new LookResult("Conflict in NameQuery between Is and EndsWith"));
                            }
                        }
                        else
                        {
                            if (wildcard1 == null)
                            {
                                wildcard1 = "*" + lookQuery.NameQuery.EndsWith;
                            }
                            else
                            {
                                wildcard1 += lookQuery.NameQuery.EndsWith;
                            }
                        }
                    }

                    if (!string.IsNullOrEmpty(lookQuery.NameQuery.Contains))
                    {
                        if (!string.IsNullOrEmpty(lookQuery.NameQuery.Is))
                        {
                            if (!lookQuery.NameQuery.Is.Contains(lookQuery.NameQuery.Contains))
                            {
                                return(new LookResult("Conflict in NameQuery between Is and Contains"));
                            }
                        }
                        else
                        {
                            if (wildcard1 == null)
                            {
                                wildcard1 = "*" + lookQuery.NameQuery.Contains + "*";
                            }
                            else
                            {
                                wildcard2 = "*" + lookQuery.NameQuery.Contains + "*";
                            }
                        }
                    }

                    var nameField = lookQuery.NameQuery.CaseSensitive ? LookConstants.NameField : LookConstants.NameField + "_Lowered";

                    if (wildcard1 != null)
                    {
                        var wildcard = lookQuery.NameQuery.CaseSensitive ? wildcard1 : wildcard1.ToLower();

                        query.Add(new WildcardQuery(new Term(nameField, wildcard)), BooleanClause.Occur.MUST);

                        if (wildcard2 != null)
                        {
                            wildcard = lookQuery.NameQuery.CaseSensitive ? wildcard2 : wildcard2.ToLower();

                            query.Add(new WildcardQuery(new Term(nameField, wildcard)), BooleanClause.Occur.MUST);
                        }
                    }

                    if (!string.IsNullOrEmpty(lookQuery.NameQuery.Is))
                    {
                        var isText = lookQuery.NameQuery.CaseSensitive ? lookQuery.NameQuery.Is : lookQuery.NameQuery.Is.ToLower();

                        query.Add(new TermQuery(new Term(nameField, isText)), BooleanClause.Occur.MUST);
                    }
                }

                #endregion

                #region DateQuery

                if (lookQuery.DateQuery != null)
                {
                    hasQuery = true;

                    query.Add(new TermQuery(new Term(LookConstants.HasDateField, "1")), BooleanClause.Occur.MUST);

                    if (lookQuery.DateQuery.After.HasValue || lookQuery.DateQuery.Before.HasValue)
                    {
                        var includeLower = lookQuery.DateQuery.After == null || lookQuery.DateQuery.Boundary == DateBoundary.Inclusive || lookQuery.DateQuery.Boundary == DateBoundary.BeforeExclusiveAfterInclusive;
                        var includeUpper = lookQuery.DateQuery.Before == null || lookQuery.DateQuery.Boundary == DateBoundary.Inclusive || lookQuery.DateQuery.Boundary == DateBoundary.BeforeInclusiveAfterExclusive;

                        query.Add(
                            new TermRangeQuery(
                                LookConstants.DateField,
                                lookQuery.DateQuery.After.DateToLuceneString() ?? DateTime.MinValue.DateToLuceneString(),
                                lookQuery.DateQuery.Before.DateToLuceneString() ?? DateTime.MaxValue.DateToLuceneString(),
                                includeLower,
                                includeUpper),
                            BooleanClause.Occur.MUST);
                    }
                }

                #endregion

                #region TextQuery

                if (lookQuery.TextQuery != null)
                {
                    hasQuery = true;

                    query.Add(new TermQuery(new Term(LookConstants.HasTextField, "1")), BooleanClause.Occur.MUST);

                    if (!string.IsNullOrWhiteSpace(lookQuery.TextQuery.SearchText))
                    {
                        var queryParser = new QueryParser(Lucene.Net.Util.Version.LUCENE_29, LookConstants.TextField, lookQuery.SearchingContext.Analyzer);

                        Query searchTextQuery = null;

                        try
                        {
                            searchTextQuery = queryParser.Parse(lookQuery.TextQuery.SearchText);
                        }
                        catch
                        {
                            return(new LookResult($"Unable to parse LookQuery.TextQuery.SearchText: '{ lookQuery.TextQuery.SearchText }' into a Lucene query"));
                        }

                        if (searchTextQuery != null)
                        {
                            query.Add(searchTextQuery, BooleanClause.Occur.MUST);

                            if (lookQuery.TextQuery.GetHighlight)
                            {
                                var queryScorer = new QueryScorer(searchTextQuery.Rewrite(lookQuery.SearchingContext.IndexSearcher.GetIndexReader()));

                                var highlighter = new Highlighter(new SimpleHTMLFormatter("<strong>", "</strong>"), queryScorer);

                                getHighlight = (x) =>
                                {
                                    var tokenStream = lookQuery.SearchingContext.Analyzer.TokenStream(LookConstants.TextField, new StringReader(x));

                                    var highlight = highlighter.GetBestFragments(
                                        tokenStream,
                                        x,
                                        1,                             // max number of fragments
                                        "...");

                                    return(new HtmlString(highlight));
                                };
                            }
                        }
                    }
                }

                #endregion

                #region TagQuery

                if (lookQuery.TagQuery != null)
                {
                    hasQuery = true;

                    query.Add(new TermQuery(new Term(LookConstants.HasTagsField, "1")), BooleanClause.Occur.MUST);

                    if (lookQuery.TagQuery.All != null)
                    {
                        if (lookQuery.TagQuery.Not != null)
                        {
                            var conflictTags = lookQuery.TagQuery.All.Where(x => !lookQuery.TagQuery.Not.Contains(x));

                            if (conflictTags.Any())
                            {
                                return(new LookResult($"Conflict in TagQuery, tags: '{ string.Join(",", conflictTags) }' are in both AllTags and NotTags"));
                            }
                        }

                        if (lookQuery.TagQuery.All.Any())
                        {
                            foreach (var tag in lookQuery.TagQuery.All)
                            {
                                query.Add(
                                    new TermQuery(new Term(LookConstants.TagsField + tag.Group, tag.Name)),
                                    BooleanClause.Occur.MUST);
                            }
                        }
                    }

                    if (lookQuery.TagQuery.Any != null)
                    {
                        if (lookQuery.TagQuery.Not != null)
                        {
                            var conflictTags = lookQuery.TagQuery.Any.Where(x => !lookQuery.TagQuery.Not.Contains(x));

                            if (conflictTags.Any())
                            {
                                return(new LookResult($"Conflict in TagQuery, tags: '{ string.Join(",", conflictTags) }' are in both AnyTags and NotTags"));
                            }
                        }

                        if (lookQuery.TagQuery.Any.Any())
                        {
                            var anyTagQuery = new BooleanQuery();

                            foreach (var tag in lookQuery.TagQuery.Any)
                            {
                                anyTagQuery.Add(
                                    new TermQuery(new Term(LookConstants.TagsField + tag.Group, tag.Name)),
                                    BooleanClause.Occur.SHOULD);
                            }

                            query.Add(anyTagQuery, BooleanClause.Occur.MUST);
                        }
                    }

                    if (lookQuery.TagQuery.Not != null && lookQuery.TagQuery.Not.Any())
                    {
                        foreach (var tag in lookQuery.TagQuery.Not)
                        {
                            query.Add(
                                new TermQuery(new Term(LookConstants.TagsField + tag.Group, tag.Name)),
                                BooleanClause.Occur.MUST_NOT);
                        }
                    }
                }

                #endregion

                #region LocationQuery

                if (lookQuery.LocationQuery != null)
                {
                    hasQuery = true;

                    query.Add(new TermQuery(new Term(LookConstants.HasLocationField, "1")), BooleanClause.Occur.MUST);

                    if (lookQuery.LocationQuery.Location != null)
                    {
                        double maxDistance = LookService.MaxDistance;

                        if (lookQuery.LocationQuery.MaxDistance != null)
                        {
                            maxDistance = Math.Min(lookQuery.LocationQuery.MaxDistance.GetMiles(), maxDistance);
                        }

                        var distanceQueryBuilder = new DistanceQueryBuilder(
                            lookQuery.LocationQuery.Location.Latitude,
                            lookQuery.LocationQuery.Location.Longitude,
                            maxDistance,
                            LookConstants.LocationField + "_Latitude",
                            LookConstants.LocationField + "_Longitude",
                            LookConstants.LocationTierFieldPrefix,
                            true);

                        filter = distanceQueryBuilder.Filter;

                        if (lookQuery.SortOn == SortOn.Distance)
                        {
                            sort = new Sort(
                                new SortField(
                                    LookConstants.DistanceField,
                                    new DistanceFieldComparatorSource(distanceQueryBuilder.DistanceFilter)));
                        }

                        getDistance = new Func <int, double?>(x =>
                        {
                            if (distanceQueryBuilder.DistanceFilter.Distances.ContainsKey(x))
                            {
                                return(distanceQueryBuilder.DistanceFilter.Distances[x]);
                            }

                            return(null);
                        });
                    }
                }

                #endregion

                if (hasQuery)
                {
                    switch (lookQuery.SortOn)
                    {
                    case SortOn.Name:     // a -> z
                        sort = new Sort(new SortField(LuceneIndexer.SortedFieldNamePrefix + LookConstants.NameField, SortField.STRING));
                        break;

                    case SortOn.DateAscending:     // oldest -> newest
                        sort = new Sort(new SortField(LuceneIndexer.SortedFieldNamePrefix + LookConstants.DateField, SortField.LONG, false));
                        break;

                    case SortOn.DateDescending:     // newest -> oldest
                        sort = new Sort(new SortField(LuceneIndexer.SortedFieldNamePrefix + LookConstants.DateField, SortField.LONG, true));
                        break;

                        // SortOn.Distance already set (if valid)
                    }

                    lookQuery.Compiled = new LookQueryCompiled(
                        lookQuery,
                        query,
                        filter,
                        sort ?? new Sort(SortField.FIELD_SCORE),
                        getHighlight,
                        getDistance);
                }
            }

            if (!hasQuery)
            {
                return(new LookResult("No query clauses supplied")); // empty failure
            }

            TopDocs topDocs = lookQuery
                              .SearchingContext
                              .IndexSearcher
                              .Search(
                lookQuery.Compiled.Query,
                lookQuery.Compiled.Filter,
                LookService.MaxLuceneResults,
                lookQuery.Compiled.Sort);

            if (topDocs.TotalHits > 0)
            {
                List <Facet> facets = null;

                if (lookQuery.TagQuery != null && lookQuery.TagQuery.FacetOn != null)
                {
                    facets = new List <Facet>();

                    Query facetQuery = lookQuery.Compiled.Filter != null
                                            ? (Query) new FilteredQuery(lookQuery.Compiled.Query, lookQuery.Compiled.Filter)
                                            : lookQuery.Compiled.Query;

                    // do a facet query for each group in the array
                    foreach (var group in lookQuery.TagQuery.FacetOn.TagGroups)
                    {
                        var simpleFacetedSearch = new SimpleFacetedSearch(
                            lookQuery.SearchingContext.IndexSearcher.GetIndexReader(),
                            LookConstants.TagsField + group);

                        var facetResult = simpleFacetedSearch.Search(facetQuery);

                        facets.AddRange(
                            facetResult
                            .HitsPerFacet
                            .Select(
                                x => new Facet()
                        {
                            Tags  = new LookTag[] { new LookTag(group, x.Name.ToString()) },
                            Count = Convert.ToInt32(x.HitCount)
                        }
                                ));
                    }
                }

                return(new LookResult(
                           LookService.GetLookMatches(
                               lookQuery.SearchingContext.IndexSearcher,
                               topDocs,
                               lookQuery.RequestFields ?? LookService.Instance.RequestFields,
                               lookQuery.Compiled.GetHighlight,
                               lookQuery.Compiled.GetDistance),
                           topDocs.TotalHits,
                           facets != null ? facets.ToArray() : new Facet[] { }));
            }

            return(new LookResult()); // empty success
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="lookQuery">The query to parse</param>
        /// <param name="parsingContext"></param>
        private static void ParseLocationQuery(ParsingContext parsingContext, LookQuery lookQuery)
        {
            if (lookQuery.LocationQuery == null)
            {
                return;
            }

            parsingContext.QueryAdd(new TermQuery(new Term(LookConstants.HasLocationField, "1")), BooleanClause.Occur.MUST);

            if (lookQuery.LocationQuery.Boundary != null) // limit results within an lat lng fixed view (eg, typical map bounds)
            {
                parsingContext.QueryAdd(
                    new TermRangeQuery(
                        LookConstants.LocationField + "_Latitude",
                        NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LatitudeMin),
                        NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LatitudeMax),
                        true,
                        true),
                    BooleanClause.Occur.MUST);

                parsingContext.QueryAdd(
                    new TermRangeQuery(
                        LookConstants.LocationField + "_Longitude",
                        NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LongitudeMin),
                        NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LongitudeMax),
                        true,
                        true),
                    BooleanClause.Occur.MUST);
            }

            if (lookQuery.LocationQuery.Location != null) // location set, so can calculate distance
            {
                double maxDistance = LookService._maxDistance;

                if (lookQuery.LocationQuery.MaxDistance != null)
                {
                    maxDistance = Math.Min(lookQuery.LocationQuery.MaxDistance.GetMiles(), maxDistance);
                }

                var distanceQueryBuilder = new DistanceQueryBuilder(
                    lookQuery.LocationQuery.Location.Latitude,
                    lookQuery.LocationQuery.Location.Longitude,
                    maxDistance,
                    LookConstants.LocationField + "_Latitude",
                    LookConstants.LocationField + "_Longitude",
                    LookConstants.LocationTierFieldPrefix,
                    true);

                parsingContext.Filter = distanceQueryBuilder.Filter;

                if (lookQuery.SortOn == SortOn.Distance)
                {
                    parsingContext.Sort = new Sort(
                        new SortField(
                            LookConstants.DistanceField,
                            new DistanceFieldComparatorSource(distanceQueryBuilder.DistanceFilter)));
                }

                parsingContext.GetDistance = new Func <int, double?>(x =>
                {
                    if (distanceQueryBuilder.DistanceFilter.Distances.ContainsKey(x))
                    {
                        return(distanceQueryBuilder.DistanceFilter.Distances[x]);
                    }

                    return(null);
                });
            }
        }
예제 #5
0
        /// <summary>
        /// Searches the lucene index with the search text.
        /// </summary>
        /// <param name="searchText">The text to search with.</param>
        /// <remarks>Syntax reference: http://lucene.apache.org/java/2_3_2/queryparsersyntax.html#Wildcard</remarks>
        /// <exception cref="SpatialSearchException">An error occured searching the lucene.net index.</exception>
        public SpatialSearchResultsModel SearchIndex(double lat, double @long, double miles)
        {
            // This check is for the benefit of the CI builds
            if (!Directory.Exists(_indexPath))
            {
                CreateIndex();
            }

            EnsureDistanceMatrixReady();

            var model = new SpatialSearchResultsModel();

            //StandardAnalyzer analyzer = new StandardAnalyzer();
            try
            {
                IndexSearcher searcher = new IndexSearcher(_indexPath, true);
                // Build query
                var dq = new DistanceQueryBuilder(lat, @long, miles, LatField, LngField, CartesianTierPlotter.DefaltFieldPrefix, true);

                //create a term query to search against all documents
                Query tq = new TermQuery(new Term("metafile", "doc"));

                var  dsort = new DistanceFieldComparatorSource(dq.DistanceFilter);
                Sort sort  = new Sort(new SortField("foo", dsort, false));

                // Perform the search, using the term query, the distance filter, and the
                // distance sort
                TopDocs    hits      = searcher.Search(tq, dq.Filter, 1000, sort);
                int        results   = hits.totalHits;
                ScoreDoc[] scoreDocs = hits.scoreDocs;

                // Get a list of distances
                Dictionary <int, Double> distances = dq.DistanceFilter.Distances;

                model.QueryLat   = lat;
                model.QueryLong  = @long;
                model.QueryMiles = miles;

                //double lastDistance = 0;
                for (int i = 0; i < results; i++)
                {
                    Document d = searcher.Doc(scoreDocs[i].doc);

                    String name         = d.Get("name");
                    double rsLat        = NumericUtils.PrefixCodedToDouble(d.Get(LatField));
                    double rsLng        = NumericUtils.PrefixCodedToDouble(d.Get(LngField));
                    int    id           = int.Parse(d.Get("PostID"));
                    Double geo_distance = distances[scoreDocs[i].doc];

                    double distance = DistanceUtils.GetInstance().GetDistanceMi(lat, @long, rsLat, rsLng);
                    double llm      = DistanceUtils.GetInstance().GetLLMDistance(lat, @long, rsLat, rsLng);

                    model.Results.Add(new SpatialResult()
                    {
                        title = name, instrumentID = id, dist = distance, lat = rsLat, lng = rsLng, resultNum = i + 1
                    });

                    //lastDistance = geo_distance;
                }
            }
            catch (Exception ex)
            {
                throw new SpatialSearchException(ex, "An error occurred while searching the spatial index.");
            }

            return(model);
        }
예제 #6
0
        /// <summary>
        ///  Main searching method
        /// </summary>
        /// <param name="lookQuery"></param>
        /// <returns>an IEnumerableWithTotal</returns>
        public static IEnumerableWithTotal <LookMatch> Query(LookQuery lookQuery)
        {
            IEnumerableWithTotal <LookMatch> lookMatches = null; // prepare return value

            if (lookQuery == null)
            {
                LogHelper.Warn(typeof(LookService), "Supplied search query was null");
            }
            else
            {
                var searchProvider = LookService.Searcher;

                var searchCriteria = searchProvider.CreateSearchCriteria();

                var query = searchCriteria.Field(string.Empty, string.Empty);

                // Text
                if (!string.IsNullOrWhiteSpace(lookQuery.TextQuery.SearchText))
                {
                    if (lookQuery.TextQuery.Fuzzyness > 0)
                    {
                        query.And().Field(LookService.TextField, lookQuery.TextQuery.SearchText.Fuzzy(lookQuery.TextQuery.Fuzzyness));
                    }
                    else
                    {
                        query.And().Field(LookService.TextField, lookQuery.TextQuery.SearchText);
                    }
                }

                // Tags
                if (lookQuery.TagQuery != null)
                {
                    var allTags = new List <string>();
                    var anyTags = new List <string>();

                    if (lookQuery.TagQuery.AllTags != null)
                    {
                        allTags.AddRange(lookQuery.TagQuery.AllTags);
                        allTags.RemoveAll(x => string.IsNullOrWhiteSpace(x));
                    }

                    if (lookQuery.TagQuery.AnyTags != null)
                    {
                        anyTags.AddRange(lookQuery.TagQuery.AnyTags);
                        anyTags.RemoveAll(x => string.IsNullOrWhiteSpace(x));
                    }

                    if (allTags.Any())
                    {
                        query.And().GroupedAnd(allTags.Select(x => LookService.TagsField), allTags.ToArray());
                    }

                    if (anyTags.Any())
                    {
                        query.And().GroupedOr(allTags.Select(x => LookService.TagsField), anyTags.ToArray());
                    }
                }

                // TODO: Date

                // TODO: Name

                // Nodes
                if (lookQuery.NodeQuery != null)
                {
                    if (lookQuery.NodeQuery.TypeAliases != null)
                    {
                        var typeAliases = new List <string>();

                        typeAliases.AddRange(lookQuery.NodeQuery.TypeAliases);
                        typeAliases.RemoveAll(x => string.IsNullOrWhiteSpace(x));

                        if (typeAliases.Any())
                        {
                            query.And().GroupedOr(typeAliases.Select(x => UmbracoContentIndexer.NodeTypeAliasFieldName), typeAliases.ToArray());
                        }
                    }

                    if (lookQuery.NodeQuery.ExcludeIds != null)
                    {
                        foreach (var excudeId in lookQuery.NodeQuery.ExcludeIds.Distinct())
                        {
                            query.Not().Id(excudeId);
                        }
                    }
                }

                try
                {
                    searchCriteria = query.Compile();
                }
                catch (Exception exception)
                {
                    LogHelper.WarnWithException(typeof(LookService), "Could not compile the Examine query", exception);
                }

                if (searchCriteria != null && searchCriteria is LuceneSearchCriteria)
                {
                    Sort   sort   = null;
                    Filter filter = null;

                    Func <int, double?>        getDistance  = x => null;
                    Func <string, IHtmlString> getHighlight = null;

                    TopDocs topDocs = null;

                    switch (lookQuery.SortOn)
                    {
                    case SortOn.Date:     // newest -> oldest
                        sort = new Sort(new SortField(LuceneIndexer.SortedFieldNamePrefix + LookService.DateField, SortField.LONG, true));
                        break;

                    case SortOn.Name:     // a -> z
                        sort = new Sort(new SortField(LuceneIndexer.SortedFieldNamePrefix + LookService.NameField, SortField.STRING));
                        break;
                    }

                    if (lookQuery.LocationQuery != null && lookQuery.LocationQuery.Location != null)
                    {
                        double maxDistance = LookService.MaxDistance;

                        if (lookQuery.LocationQuery.MaxDistance != null)
                        {
                            maxDistance = Math.Min(lookQuery.LocationQuery.MaxDistance.GetMiles(), maxDistance);
                        }

                        var distanceQueryBuilder = new DistanceQueryBuilder(
                            lookQuery.LocationQuery.Location.Latitude,
                            lookQuery.LocationQuery.Location.Longitude,
                            maxDistance,
                            LookService.LocationField + "_Latitude",
                            LookService.LocationField + "_Longitude",
                            CartesianTierPlotter.DefaltFieldPrefix,
                            true);

                        // update filter
                        filter = distanceQueryBuilder.Filter;

                        if (lookQuery.SortOn == SortOn.Distance)
                        {
                            // update sort
                            sort = new Sort(
                                new SortField(
                                    LookService.DistanceField,
                                    new DistanceFieldComparatorSource(distanceQueryBuilder.DistanceFilter)));
                        }

                        // raw data for the getDistance func
                        var distances = distanceQueryBuilder.DistanceFilter.Distances;

                        // update getDistance func
                        getDistance = new Func <int, double?>(x =>
                        {
                            if (distances.ContainsKey(x))
                            {
                                return(distances[x]);
                            }

                            return(null);
                        });
                    }

                    var indexSearcher = new IndexSearcher(((LuceneIndexer)LookService.Indexer).GetLuceneDirectory(), false);

                    var luceneSearchCriteria = (LuceneSearchCriteria)searchCriteria;

                    // Do the Lucene search
                    topDocs = indexSearcher.Search(
                        luceneSearchCriteria.Query,                         // the query build by Examine
                        filter ?? new QueryWrapperFilter(luceneSearchCriteria.Query),
                        LookService.MaxLuceneResults,
                        sort ?? new Sort(SortField.FIELD_SCORE));

                    if (topDocs.TotalHits > 0)
                    {
                        // setup the highlighing func if required
                        if (lookQuery.TextQuery.HighlightFragments > 0 && !string.IsNullOrWhiteSpace(lookQuery.TextQuery.SearchText))
                        {
                            var version = Lucene.Net.Util.Version.LUCENE_29;

                            Analyzer analyzer = new StandardAnalyzer(version);

                            var queryParser = new QueryParser(version, LookService.TextField, analyzer);

                            var queryScorer = new QueryScorer(queryParser
                                                              .Parse(lookQuery.TextQuery.SearchText)
                                                              .Rewrite(indexSearcher.GetIndexReader()));

                            Highlighter highlighter = new Highlighter(new SimpleHTMLFormatter("<strong>", "</strong>"), queryScorer);

                            // update the func so it does real highlighting work
                            getHighlight = (x) =>
                            {
                                var tokenStream = analyzer.TokenStream(LookService.TextField, new StringReader(x));

                                var highlight = highlighter.GetBestFragments(
                                    tokenStream,
                                    x,
                                    lookQuery.TextQuery.HighlightFragments,                             // max number of fragments
                                    lookQuery.TextQuery.HighlightSeparator);                            // fragment separator

                                return(new HtmlString(highlight));
                            };
                        }

                        lookMatches = new EnumerableWithTotal <LookMatch>(
                            LookSearchService.GetLookMatches(
                                lookQuery,
                                indexSearcher,
                                topDocs,
                                getHighlight,
                                getDistance),
                            topDocs.TotalHits);
                    }
                }
            }

            return(lookMatches ?? new EnumerableWithTotal <LookMatch>(Enumerable.Empty <LookMatch>(), 0));
        }