ElasticSearch QueryBuilder must_not子句奇怪的行为

时间:2018-09-15 14:10:02

标签: java elasticsearch

根据文档

  

必须不子句(查询)不得出现在匹配的文档中。

我有这样的查询:

// searching for URI which contains smart and doesn't contain vip.vs.csin.cz
BoolQueryBuilder builder = QueryBuilders.boolQuery();
builder.must(QueryBuilders.termQuery(URI, "smart")));
builder.mustNot(QueryBuilders.termQuery(URI, "vip.vs.csin.cz")));

我的Elasticsearch存储库中有两个URI

1)

  

/smart-int-vip.vs.csin.cz:5080/smart/api/runtime/case/SC0000000000558648/record/generate/4327/by/SMOBVA002/as/true?espisRecordForm=ANALOG&accountNumber=2318031033/0800 < / p>

2)

  

/ smart / api / runtime / case / SC0000000000558648 / record / generate / 4327 / by / SMOBVA002 / as / true?espisRecordForm = ANALOG&accountNumber = 2318031033/0800

当我通过 ElasticSearchTemplate

执行查询时
elasticsearchTemplate.getClient().search(searchRequest);

我找回 0条记录。当我执行不带 mustNot 子句的相同查询时,我会得到 2条记录。
在kibana中,我可以写:

uri: "smart" NOT uri: "vip.vs.csin.cz"

并按预期获得 1条记录

我期待Java ElasticSearchClient出现相同的行为。如何过滤Java中包含“ vip.vs.csin.cz”的记录,以及为什么它过滤了第二条记录,即使它不包含我指定的mustNot子句中的任何内容也是如此?

编辑这是我的映射

@Document(indexName = "audit-2018", type = "audit")
public class Trace {

    @Id
    private String id;
    @Field(type = FieldType.Text)
    private String uri;

    // more columns, getter & setters
}

1 个答案:

答案 0 :(得分:1)

您提供的Java代码显示了使用mustmust_not子句的布尔查询,其中您正在执行术语查询。关于字词查询的问题在于,它们取决于您在字段中使用的分析器,text(这是您的uri字段,read more here)的数据类型的标准分析器将删除所有标点符号(换句话说,单词中的点)并将单词拆分。 vip.vs.csin.cz成为vip vs csin cztext字段类型应仅保留用于全文搜索,在这种情况下,我会选择keyword字段类型(read more here)Kibana查询按预期运行的原因是一个人实际上不是在进行术语查询,而是在一个query_string查询中包含一个Lucene查询:uri: "smart" NOT uri: "vip.vs.csin.cz"

因此,您有两种选择可以解决您的问题。您可以将条款查询更改为match_phrase查询,这将允许您保留标记化条款的顺序,并可能获得正确的结果。一种替代方法是在Java代码中执行query_string查询而不是术语查询,因为您已经确定这样做确实可以提供正确的结果。

但是,我建议的解决方案是将uri的字段类型为keyword进行索引,因为此字段类型不会导致将字段值不必要地标记为多个术语。您可以了解有关keyword字段类型here的默认分析器和标记器的更多信息。因为您知道查询完全“按原样”匹配您的字段值,所以这将在将来为您省去麻烦。