简体   繁体   English

带有Nest字段的查询提升没有从Elasticsearch返回结果

[英]Query with Nest field boosting returning no results from Elasticsearch

I'm having real problems getting a query using field boosting to work with Elasticsearch. 我在使用字段增强与Elasticsearch一起使用来获取查询时遇到了实际问题。 I've been through the Nest docs on the topic, but they weren't particularly helpful, so my code is really based on the solution to this question: Elastic Search using NEST Field Boosting . 我已经阅读过有关该主题的Nest文档,但是它们并不是特别有用,因此我的代码确实基于以下问题的解决方案: 使用NEST Field Boosting进行弹性搜索

If I run the following query I get one result, as expected: 如果运行以下查询,则会得到一个预期的结果:

var matches =
    _client.Search<SearchableMerchant>(
        s => s.From((page - 1) * pageSize)
            .Size(pageSize)
            .QueryString("*test*")
            .MinScore(1)
    );

However, if I try to use field boosting, using the following, I get no matches: 但是,如果我尝试使用字段增强,则使用以下命令,将找不到任何匹配项:

var matches =
            _client.Search<SearchableMerchant>(
                s => s.From((page - 1) * pageSize)
                    .Size(pageSize)
                    .Query(q => q
                        .Boosting(bq => bq
                            .Positive(pq => pq
                                .CustomScore(cbf => cbf
                                    .Query(cbfq => cbfq
                                        .QueryString(
                                            qs => qs
                                            .OnFieldsWithBoost(d => d
                                                .Add("opportunities.acquirerLocationMID", Math.Pow(2, 17))
                                                .Add("opportunities.amexMID", Math.Pow(2, 16))
                                                .Add("opportunities.epayMID", Math.Pow(2, 16))
                                                .Add("v1MerchantId", Math.Pow(2, 16))
                                                .Add("locatorId", Math.Pow(2, 15))
                                                .Add("opportunities.opportunityLocatorId", Math.Pow(2, 14))
                                                .Add("businessName", Math.Pow(2, 13))
                                                .Add("searchablePhone", Math.Pow(2, 12))
                                                .Add("address.postCodeDetails.postCode.postCode", Math.Pow(2, 11))
                                                .Add("contacts.contact.searchableEmailAddress", Math.Pow(2, 11))
                                                .Add("contacts.contact.searchableMainPhone", Math.Pow(2, 10))
                                                .Add("contacts.contact.searchableMobilePhone", Math.Pow(2, 10))
                                                .Add("contacts.contact.fullName", Math.Pow(2, 9))
                                                .Add("contacts.contact.surname", Math.Pow(2, 8))
                                                .Add("contacts.contact.firstName", Math.Pow(2, 7))
                                                .Add("searchableAddress", Math.Pow(2, 6))
                                                .Add("ownershipUser.username", Math.Pow(2, 5))
                                                .Add("ownershipUser.searchableFullName", Math.Pow(2, 4))
                                                .Add("ownershipUser.lastName", Math.Pow(2, 3))
                                                .Add("ownershipUser.firstName", Math.Pow(2, 2))
                                                .Add("opportunities.depositAccount", Math.Pow(2, 1))
                                                .Add("opportunities.depositIban", Math.Pow(2, 1))
                                                .Add("opportunities.feesAccount", Math.Pow(2, 1))
                                                .Add("opportunities.feesIban", Math.Pow(2, 1))
                                                //  TODO: Company registration number - somewhere in legal methinks
                                            )
                                            .Query(
                                                "*test*"
                                            )
                                        )
                                    )
                                )
                            )
                            .Negative(nq => nq
                                .Filtered(nfq => nfq
                                    .Query(qq => qq.MatchAll())
                                    .Filter(f =>
                                        f.Missing("opportunities.acquirerLocationMID")
                                        && f.Missing("opportunities.amexMID")
                                        && f.Missing("opportunities.epayMID")
                                        && f.Missing("v1MerchantId")
                                        && f.Missing("locatorId")
                                        && f.Missing("opportunities.opportunityLocatorId")
                                        && f.Missing("businessName")
                                        && f.Missing("searchablePhone")
                                        && f.Missing("address.postCodeDetails.postCode.postCode")
                                        && f.Missing("contacts.contact.searchableEmailAddress")
                                        && f.Missing("contacts.contact.searchableMainPhone")
                                        && f.Missing("contacts.contact.searchableMobilePhone")
                                        && f.Missing("contacts.contact.fullName")
                                        && f.Missing("contacts.contact.surname")
                                        && f.Missing("contacts.contact.firstName")
                                        && f.Missing("searchableAddress")
                                        && f.Missing("ownershipUser.username")
                                        && f.Missing("ownershipUser.searchableFullName")
                                        && f.Missing("ownershipUser.lastName")
                                        && f.Missing("ownershipUser.firstName")
                                        && f.Missing("opportunities.depositAccount")
                                        && f.Missing("opportunities.depositIban")
                                        && f.Missing("opportunities.feesAccount")
                                        && f.Missing("opportunities.feesIban")
                                    )
                                )
                            )
                            .NegativeBoost(0.01)
                        )
                    )
                    .MinScore(1)
            );

I realise this code could be better structured, but right now I just want to get a field boosting query working - I'll tidy it later. 我意识到这段代码的结构可能更好,但是现在我只想让字段提升查询正常工作-我待会儿整理一下。

Here are some things I've tried: 这是我尝试过的一些方法:

  1. The Nest docs are silent on the topic of whether you can use OnFieldsWithBoost with property names. Nest文档对是否可以使用带有属性名称的OnFieldsWithBoost保持沉默。 Ie, is this OK? 即可以吗?

    .OnFieldsWithBoost(d => d .Add("businessName", Math.Pow(2, 13)) .OnFieldsWithBoost(d => d .Add(“ businessName”,Math.Pow(2,13))

As opposed this? 反对呢?

.OnFieldsWithBoost(d => d
    .Add(m => m.businessName, Math.Pow(2, 13))

The reason I ask is that I have sub-properties I want to boost that sit within collections. 我问的原因是我有一些要提升集合中的子属性。 For example, opportunities.opportunityLocatorId . 例如, opportunities.opportunityLocatorId Opportunities obviously being the collection, and I want to match where any object in that collection has a matching value for its opportunityLocatorId field. 机会显然是集合,我想匹配该集合中任何对象具有其opportunityLocatorId字段都具有匹配值的位置。

This works with fields - you can use a lambda or a string - but does it work with boosting? 这适用于字段-您可以使用lambda或字符串-但它可以与boosting一起使用吗?

No idea, but I've tried it both ways, slimming down the query to just include a boost for businessName , since this is the field that should match the string 'test', but still no results come back. 不知道,但是我已经尝试了两种方法,将查询的范围缩小到只包含一个对businessName的增强,因为这是应该与字符串“ test”匹配的字段,但仍然没有结果返回。

I've also tried getting rid of the .Negative clause, just in case that was matching something it shouldn't. 我还尝试摆脱.Negative子句,以防万一它匹配了不该匹配的东西。 It's there to deboost any query where no match is found in any of the fields listed in the .Positive clause. .Positive子句中列出的任何字段中都找不到匹配项的情况下,可以消除任何查询。 Still no results. 仍然没有结果。

I've also upped the .NegativeBoost value to 1 (ie, no effect, so any results shouldn't be filtered down to a score below 1 that didn't start out with such a low score) but, again, no dice. 我还将.NegativeBoost值提高到了1(即没有效果,因此,不应将任何结果过滤到低于1的分数,而该分数并非以如此低的分数开始),但还是没有骰子。

Here's the content of my index, just so you can see that the businessName field should match 'test' with the second query, as it does with the first: 这是索引的内容,因此您可以看到businessName字段应与第二个查询匹配“ test”,就像第一个查询一样:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 1.0,
    "hits" : [ {
      "_index" : "merchantv2",
      "_type" : "searchablemerchant",
      "_id" : "00000000-0000-0000-0000-000000000000",
      "_score" : 1.0,
      "_source":{"merchantGuid":"00000000-0000-0000-0000-000000000000","v1MerchantId":0,"locatorId":"0","address":{"addressGuid":"00000000-0000-0000-0000-000000000000","postCodeDetails":{"postCodeKey":0,"postalDistrict":{"postalDistrictKey":0,"postalDistrict":""},"postalLocation":"0","latitude":0.0,"longitude":0.0,"townName":"None","countyKey":0,"countryKey":0,"postCode":{"postCodeKey":0,"postCode":" 0"}},"county":{"countyKey":0,"countyName":"","countryKey":0,"recStatus":3,"countryKeyValue":0},"countryKey":0,"addressTypeKey":0,"updateDate":"0001-01-01T00:00:00+00:00","createdDate":"2016-01-07T19:46:28.4463+00:00"},"searchableAddress":" 0","searchablePhone":"","searchableFax":"","businessName":"","contacts":[],"opportunities":[{"opportunityGuid":"00000000-0000-0000-0000-000000000000","merchantGuid":"00000000-0000-0000-0000-000000000000","location":{"locationGuid":"00000000-0000-0000-0000-000000000000","tradingAddress":{"verified":false,"addressGuid":"00000000-0000-0000-0000-000000000000","postCodeDetails":{"postCodeKey":0,"postalDistrict":{"postalDistrictKey":0,"postalDistrict":""},"postalLocation":"0","latitude":0.0,"longitude":0.0,"townName":"None","countyKey":0,"countryKey":0,"postCode":{"postCodeKey":0,"postCode":" 0"}},"county":{"countyKey":0,"countyName":"","countryKey":0,"recStatus":3,"countryKeyValue":0},"countryKey":0,"addressTypeKey":0,"updateDate":"0001-01-01T00:00:00+00:00","createdDate":"2016-01-07T19:46:28.4463+00:00"}},"opportunityLocatorId":"000000"}]}
    }, {
      "_index" : "merchantv2",
      "_type" : "searchablemerchant",
      "_id" : "5f55fe61-ca65-e411-93f3-0cc47a07ef4a",
      "_score" : 1.0,
      "_source":{"merchantGuid":"5f55fe61-ca65-e411-93f3-0cc47a07ef4a","locatorId":"PM227Z02","address":{"addressGuid":"5c55fe61-ca65-e411-93f3-0cc47a07ef4a","houseNumber":"242","streetName":"Acklam Road","houseName":"","flatAptSuite":"","townName":"London","postCodeDetails":{"postCodeKey":1,"postalDistrict":{"postalDistrictKey":2782,"postalDistrict":"W10"},"postalLocation":"5JJ","latitude":51.52094651,"longitude":-0.20149990,"townName":"London","countyKey":0,"countryKey":224,"postCode":{"postCodeKey":1,"postCode":"W10 5JJ"}},"county":{"countyKey":626,"countyName":"Kensington And Chelsea","countryKey":224,"recStatus":1,"countryKeyValue":224},"countryKey":224,"addressTypeKey":0,"updateDate":"0001-01-01T00:00:00+00:00","createdDate":"2016-01-07T19:46:28.4653+00:00"},"searchableAddress":"242 Acklam Road, London, Kensington And Chelsea, W10 5JJ","searchablePhone":"+44 2031954484","searchableFax":"","businessName":"Test Merchant","contacts":[],"opportunities":[]}
    } ]
  }
}

I'm using Elasticsearch 1.7.1 and Nest 1.7.1 on Windows 7 (yeah, I know, but it's what the client uses) with .NET 4.5.1. 我在.NET 4.5.1上的Windows 7上使用Elasticsearch 1.7.1和Nest 1.7.1(是的,我知道,但这是客户端使用的)。

I've also tried capturing the traffic going between my Web API and elasticsearch, but to no avail. 我也尝试捕获Web API和elasticsearch之间的流量,但无济于事。 Possibly a config issue but neither Fiddler nor Wireshark/npcap is able to capture the traffic between these two, both running on the local machine, so I can't see the actual request being sent to elasticsearch, which I suspect would be helpful. 可能是配置问题,但是Fiddler或Wireshark / npcap都无法捕获这两者都在本地计算机上运行的流量,因此我看不到实际的请求被发送到elasticsearch,我怀疑这会有所帮助。 Basically I was wondering if any error was coming back from Elasticsearch that Nest was swallowing. 基本上,我想知道是否有任何错误从Elasticsearch回来,表明Nest被吞噬了。

Well... the intuition turned out to be correct. 好吧...直觉是正确的。 Here's a sample of what's appearing in the elasticsearch log file: 这是elasticsearch日志文件中出现的示例:

[2016-01-08 10:14:01,534][DEBUG][action.search.type       ] [Rocket Racer] All shards failed for phase: [query]
org.elasticsearch.search.SearchParseException: [user][4]: from[0],size[20]: Parse Failure [Failed to parse source [{
  "from": 0,
  "size": 20,
  "min_score": 1.0,
  "query": {
    "boosting": {
      "positive": {
        "custom_score": {
          "query": {
            "query_string": {
              "query": "*test*",
              "fields": [
                "opportunities.acquirerLocationMID^131072",
                "opportunities.amexMID^65536",
                "opportunities.epayMID^65536",
                "v1MerchantId^65536",
                "locatorId^32768",
                "opportunities.opportunityLocatorId^16384",
                "businessName^8192",
                "searchablePhone^4096",
                "address.postCodeDetails.postCode.postCode^2048",
                "contacts.contact.searchableEmailAddress^2048",
                "contacts.contact.searchableMainPhone^1024",
                "contacts.contact.searchableMobilePhone^1024",
                "contacts.contact.fullName^512",
                "contacts.contact.surname^256",
                "contacts.contact.firstName^128",
                "searchableAddress^64",
                "ownershipUser.username^32",
                "ownershipUser.searchableFullName^16",
                "ownershipUser.lastName^8",
                "ownershipUser.firstName^4",
                "opportunities.depositAccount^2",
                "opportunities.depositIban^2",
                "opportunities.feesAccount^2",
                "opportunities.feesIban^2"
              ]
            }
          }
        }
      },
      "negative": {
        "filtered": {
          "query": {
            "match_all": {}
          },
          "filter": {
            "bool": {
              "must": [
                {
                  "missing": {
                    "field": "opportunities.acquirerLocationMID"
                  }
                },
                {
                  "missing": {
                    "field": "opportunities.amexMID"
                  }
                },
                {
                  "missing": {
                    "field": "opportunities.epayMID"
                  }
                },
                {
                  "missing": {
                    "field": "v1MerchantId"
                  }
                },
                {
                  "missing": {
                    "field": "locatorId"
                  }
                },
                {
                  "missing": {
                    "field": "opportunities.opportunityLocatorId"
                  }
                },
                {
                  "missing": {
                    "field": "businessName"
                  }
                },
                {
                  "missing": {
                    "field": "searchablePhone"
                  }
                },
                {
                  "missing": {
                    "field": "address.postCodeDetails.postCode.postCode"
                  }
                },
                {
                  "missing": {
                    "field": "contacts.contact.searchableEmailAddress"
                  }
                },
                {
                  "missing": {
                    "field": "contacts.contact.searchableMainPhone"
                  }
                },
                {
                  "missing": {
                    "field": "contacts.contact.searchableMobilePhone"
                  }
                },
                {
                  "missing": {
                    "field": "contacts.contact.fullName"
                  }
                },
                {
                  "missing": {
                    "field": "contacts.contact.surname"
                  }
                },
                {
                  "missing": {
                    "field": "contacts.contact.firstName"
                  }
                },
                {
                  "missing": {
                    "field": "searchableAddress"
                  }
                },
                {
                  "missing": {
                    "field": "ownershipUser.username"
                  }
                },
                {
                  "missing": {
                    "field": "ownershipUser.searchableFullName"
                  }
                },
                {
                  "missing": {
                    "field": "ownershipUser.lastName"
                  }
                },
                {
                  "missing": {
                    "field": "ownershipUser.firstName"
                  }
                },
                {
                  "missing": {
                    "field": "opportunities.depositAccount"
                  }
                },
                {
                  "missing": {
                    "field": "opportunities.depositIban"
                  }
                },
                {
                  "missing": {
                    "field": "opportunities.feesAccount"
                  }
                },
                {
                  "missing": {
                    "field": "opportunities.feesIban"
                  }
                }
              ]
            }
          }
        }
      },
      "negative_boost": 0.01
    }
  }
}]]
    at org.elasticsearch.search.SearchService.parseSource(SearchService.java:747)
    at org.elasticsearch.search.SearchService.createContext(SearchService.java:572)
    at org.elasticsearch.search.SearchService.createAndPutContext(SearchService.java:544)
    at org.elasticsearch.search.SearchService.executeQueryPhase(SearchService.java:306)
    at org.elasticsearch.search.action.SearchServiceTransportAction$5.call(SearchServiceTransportAction.java:231)
    at org.elasticsearch.search.action.SearchServiceTransportAction$5.call(SearchServiceTransportAction.java:228)
    at org.elasticsearch.search.action.SearchServiceTransportAction$23.run(SearchServiceTransportAction.java:559)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: org.elasticsearch.index.query.QueryParsingException: [user] No query registered for [custom_score]
    at org.elasticsearch.index.query.QueryParseContext.parseInnerQuery(QueryParseContext.java:303)
    at org.elasticsearch.index.query.BoostingQueryParser.parse(BoostingQueryParser.java:63)
    at org.elasticsearch.index.query.QueryParseContext.parseInnerQuery(QueryParseContext.java:305)
    at org.elasticsearch.index.query.IndexQueryParserService.innerParse(IndexQueryParserService.java:382)
    at org.elasticsearch.index.query.IndexQueryParserService.parse(IndexQueryParserService.java:281)
    at org.elasticsearch.index.query.IndexQueryParserService.parse(IndexQueryParserService.java:276)
    at org.elasticsearch.search.query.QueryParseElement.parse(QueryParseElement.java:33)
    at org.elasticsearch.search.SearchService.parseSource(SearchService.java:731)
    ... 9 more

So what am I doing wrong? 那我在做什么错? Does anyone know how to fix the second query, which elasticsearch clearly doesn't like? 有谁知道如何解决第二个查询,而elasticsearch显然不喜欢该查询? And is there some way of getting any erorrs out of Nest? 有什么办法可以使Nest摆脱任何错误? I'd expect an exception, but that's not happening - it just returns silently with an empty match collection, and there's no property on the collection that indicates something went wrong. 我希望有一个异常,但是不会发生-它只是以一个空的match集合静默返回,并且该集合上没有任何属性表明发生了问题。

Any help gratefully received. 非常感谢任何帮助。

Thanks! 谢谢!

Bart 巴特

The custom score query was deprecated in Elasticsearch 0.90.4 and removed in Elasticsearch 1.x. 自定义分数查询在Elasticsearch 0.90.4中已弃用,在Elasticsearch 1.x中已删除。 It's kept in NEST for backwards compatibility. 保留在NEST中以实现向后兼容性。 Instead, you should use the function score query . 相反,您应该使用功能得分查询

NEST however should have indicated that an error occurred via the IsValid property, which should be false in this case. 但是NEST应该已经通过IsValid属性指示发生了错误,在这种情况下应该为false By default, NEST 1.x doesn't throw on Elasticsearch exceptions. 默认情况下,NEST 1.x不会引发Elasticsearch异常。 You can enable this behavior by setting ThrowOnElasticsearchServerExceptions() on your ConnectionSettings . 您可以通过在ConnectionSettings上设置ThrowOnElasticsearchServerExceptions()来启用此行为。

Side note: Using a wildcard in the beginning of the term (eg *test ) is generally bad practice as it will cause every single term in the index to be examined. 旁注:在术语的开头(例如*test )使用通配符通常是不好的做法,因为这将导致检查索引中的每个单个术语。 You may want to look into modifying your mappings and use something like the nGram tokenizer instead. 您可能需要研究修改映射,并使用类似nGram令牌生成器的方法。

Turns out that what I'm trying to do is pretty simple, and I'd just disappeared down the wrong rabbit hole for a while. 事实证明,我要做的事情很简单,我只是在错误的兔子洞里消失了一段时间。 For example, here's a multi_match query to which I've applied field boosting: 例如,这是我应用了字段增强的multi_match查询:

curl -XGET http://localhost:9200/merchantv2/_search -d '
{
    "query": {
        "multi_match": {
            "query": "test",
            "type": "phrase_prefix",
            "fields" : ["businessName^3", "address.streetName"]
        }
    }
}'

In this case I've boosted the businessName field such that matches found in it are three times as important as those found in address.streetName . 在这种情况下,我增强了businessName字段,以使在其中找到的匹配项比在address.streetName中找到的匹配项重要三倍。 Seems to be working just fine. 似乎工作正常。

Here's a link to the relevant documentation: https://www.elastic.co/guide/en/elasticsearch/reference/1.7/query-dsl-multi-match-query.html (props to Val for this, which he suggested for a different question). 以下是相关文档的链接: https : //www.elastic.co/guide/zh-cn/elasticsearch/reference/1.7/query-dsl-multi-match-query.html (为此,他建议使用Val)一个不同的问题)。

Thanks for the pointers! 感谢您的指点!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM