【问题标题】:ElasticSearch term query returns 0 hits although document exists尽管文档存在,但 ElasticSearch 术语查询返回 0 个命中
【发布时间】:2021-06-07 03:37:52
【问题描述】:

我有一个 ES 域,当我使用文档的 emailId 字段查询时,我没有得到任何点击。但是,此字段和值存在于文档中。对于同一文档,通过employeeId 查询有效。 下面是我的索引映射的样子。

{
  "properties": {
    "employeeId": {
      "type": "text",
      "fields": {
        "keyword": {
          "ignore_above": 256,
          "type": "keyword"
        }
      }
    },
    "emailId": {
      "type": "text",
      "fields": {
        "keyword": {
          "ignore_above": 256,
          "type": "keyword"
        }
      }
    }
  }
}

以下是我运行搜索的方式。

public SearchResponse searchForExactDocument(final String indexName, final Map<String, Object> queryMap)
            throws IOException {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryMap.forEach((name, value) -> {
            queryBuilder.must(QueryBuilders.termQuery(name, value));
        });
        return this.executeSearch(indexName, queryBuilder);
    }

private SearchResponse executeSearch(final String indexName, final QueryBuilder queryBuilder) throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(indexName);
        searchRequest.source(searchSourceBuilder);
        return restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    }

我运行了 SearcRequest.source().toString(),下面是我得到的搜索的源字符串。

{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "emailId": {
              "value": "21june6lambdatest7@gmail.com",
              "boost": 1.0
            }
          }
        }
      ],
      "adjust_pure_negative": true,
      "boost": 1.0
    }
  }
}

下面是应该返回但没有得到任何点击的文档。

index{
  [
    person
  ][
    _doc
  ][
    null
  ],
  source[
    {
      "firstName": "MyEmployee",
      "lastName": "June6Test7",
      "emailId": "21june6lambdatest7@gmail.com",
      "employeeId": "13908528"
    }
  ]
}

我发现使用employeeId 的查询可以正常工作但emailId 无法正常工作,这很奇怪。任何帮助将不胜感激。

更新: 以下是我的索引创建方法。

public CreateIndexResponse createIndex(final CreateIndexInput createIndexInput) throws IOException {
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(createIndexInput.indexName());
        Settings.Builder settingsBuilder = Settings.builder();
        settingsBuilder.put(NUMBER_OF_SHARDS_KEY, createIndexInput.numOfShards());
        settingsBuilder.put(NUMBER_OF_REPLICAS, createIndexInput.numOfReplicas());
        settingsBuilder.put("analysis.analyzer.custom_uax_url_email.tokenizer", "uax_url_email");
        createIndexInput.mapping().ifPresent(mapping ->
                createIndexRequest.mapping(mapping, XContentType.JSON));
        createIndexRequest.settings(settingsBuilder.build());
        return restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
    }

【问题讨论】:

    标签: elasticsearch elastic-stack aws-elasticsearch elasticsearch-7 resthighlevelclient


    【解决方案1】:

    术语查询返回在提供的字段中包含确切术语的文档。您需要将 .keyword 添加到 emailId 字段。这使用关键字分析器而不是标准分析器(注意 emailId 字段后面的“.keyword”)。

    如果没有指定分析器,默认情况下text 类型字段使用standard analyzer。这会将“21june6lambdatest7@gmail.com”分解为以下标记

    {
      "tokens": [
        {
          "token": "21june6lambdatest7",
          "start_offset": 0,
          "end_offset": 18,
          "type": "<ALPHANUM>",
          "position": 0
        },
        {
          "token": "gmail.com",
          "start_offset": 19,
          "end_offset": 28,
          "type": "<ALPHANUM>",
          "position": 1
        }
      ]
    }
    

    您需要将查询修改为

    {
      "query": {
        "bool": {
          "must": [
            {
              "term": {
                "emailId.keyword": {                // note this
                  "value": "21june6lambdatest7@gmail.com",
                  "boost": 1.0
                }
              }
            }
          ],
          "adjust_pure_negative": true,
          "boost": 1.0
        }
      }
    }
    

    更新 1: 根据下面的 cmets,将您的索引映射和设置修改为

    {
      "settings": {
        "analysis": {
          "analyzer": {
            "my_analyzer": {
              "tokenizer": "my_tokenizer"
            }
          },
          "tokenizer": {
            "my_tokenizer": {
              "type": "uax_url_email"
            }
          }
        }
      },
      "mappings": {
        "properties": {
          "emailId": {
            "type": "text",
            "analyzer":"my_analyzer"
          }
        }
      }
    }
    

    搜索查询:

    {
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "emailId": "21june6lambdatest7@gmail.com"
              }
            }
          ],
          "adjust_pure_negative": true,
          "boost": 1.0
        }
      }
    }
    

    搜索结果:

     "hits": [
          {
            "_index": "67823510",
            "_type": "_doc",
            "_id": "1",
            "_score": 0.6931471,
            "_source": {
              "emailId": "21june6lambdatest7@gmail.com"
            }
          }
        ]
    

    【讨论】:

    • 非常感谢您提供的帮助。因此,要从 RestHighLevelClient Java 库中执行此操作,这样做是否有意义? Settings settings = Settings.builder() .put("analysis.analyzer.custom_uax_url_email.type", "custom") .put("analysis.analyzer.custom_uax_url_email.tokenizer", "uax_url_email") .build();
    • 或者有更好的方法吗?
    • @AnOldSoul 当您查询电子邮件 id 时,最好使用 UAX URL 电子邮件标记器 --> elastic.co/guide/en/elasticsearch/reference/current/… 我可以为您提供一个相同的工作示例吗?
    • 知道了,您能否指出我可以将 UAX URL 电子邮件标记器与我的 Java 搜索方法一起使用的方向?
    • @AnOldSoul 您需要在索引设置中定义一个分析器(使用此标记器),然后在您的索引映射中为emailId 字段使用此定义的分析器。请仔细阅读答案的更新部分,如果这能解决您的问题,请告诉我?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多