【问题标题】:Elasticsearch - searching with "keyword" type don't workElasticsearch - 使用“关键字”类型搜索不起作用
【发布时间】:2018-02-02 17:10:24
【问题描述】:

我使用 Elasticsearch Java REST 客户端 6.1。当我尝试查找由于几个参数而不是在一个字段中的日志时,我什么也得不到。

这是我的代码:

 @Override
    public SearchResponse findLogsByValues(ElasticSearchLogRequest esLogRequest, Pageable pageable) {
        SearchRequest searchRequest = new SearchRequest("portal-logs-*");

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder bqb = QueryBuilders.boolQuery();
 if (esLogRequest.getLevels() != null) {
            Iterator<String> iterator = esLogRequest.getLevels().iterator();
            int counter = 0;
            SpanOrQueryBuilder spanOrQueryBuilder = null;
            while (iterator.hasNext()) {
                if (counter == 0) {
                    spanOrQueryBuilder = new SpanOrQueryBuilder(QueryBuilders.
                            spanTermQuery("level", iterator.next().toLowerCase()));
                } else {
                    spanOrQueryBuilder.addClause(QueryBuilders.
                            spanTermQuery("level", iterator.next().toLowerCase()));
                }
                counter++;
            }
            bqb.filter(spanOrQueryBuilder);
        }
 try {
            searchResponse = client.search(searchRequest);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return searchResponse;
    }

这是我的 json 请求:

{

    "levels": ["TRACE","INFO"]

}

这是日志(对象)在 ES 中的样子:

{
    "code": 200,
    "error": "",
    "message": "",
    "data": {
        "content": [
                    {
                    "level": "INFO",
                    "module": "test module",
                    "ip": "192.168.3.93",
                    "thread": "test thread",
                    "sessionId": "1",
                    "office": "1",
                    "message": "test message 3",
                    "userName": "user",
                    "timeStamp": "2018-01-25T08:02:50.000Z",
                    "userLogin": "user",
                    "node": "first node",
                    "system": "super system 1",
                    "port": 9300,
                    "header": "test Header",
                    "submodule": "test submodule",
                    "location": {
                        "lon": -71.34,
                        "lat": 41.12
                    },
                    "operation": "some operation",
                    "device": "some device"
        }
        ],
        "totalPages": 1,
        "last": true,
        "totalElements": 0,
        "size": 0,
        "number": 0,
        "sort": null,
        "first": true,
        "numberOfElements": 0
    }
}

这是我的映射模板:

  PUT _template/portal-logs
{
  "template": "portal-logs-*",
  "settings": { "number_of_shards": 5 },
  "mappings": {
      "logs_info": {
        "_all": {
          "enabled": false
        },
        "properties": {
          "device": {"type": "keyword"},
          "header": {"type": "text"},
          "ip": {"type": "keyword"},
          "level": {"type": "keyword"},
          "location": {"type": "geo_point"},
          "message": {"type": "text"},
          "module": {"type": "keyword"},
          "node": {"type": "keyword"},
          "office": {"type": "keyword"},
          "operation": {"type": "keyword"},
          "port": {"type": "integer"},
          "sessionId": {"type": "keyword"},
          "submodule": {"type": "keyword"},
          "system": {"type": "keyword"},
          "thread": {"type": "keyword"},
          "timeStamp": {"type": "date"},
          "userLogin": {"type": "keyword"},
          "userName": {"type": "keyword"}
        }
      }
    }
  }

因此,当在映射字段“级别”并将其设置为“文本”时 - 它工作正常但是当我设置“关键字”时 - 我收到一个空的 json。 我需要该字段“级别”具有严格的类型“关键字”,并且当我想获取所有具有“级别”“INFO”或“TRACE”的日志时它必须工作。 在这种情况下我该怎么办?为什么使用关键字不起作用?

【问题讨论】:

  • 如果您删除 .toLowerCase() 它应该可以正常工作吗?因为您搜索的是INFO 而不是info。同时使用TermQuery 而不是SpanTermQuery
  • 当我删除 .toLowerCase() 它也不起作用。当我想使用搜索一个或另一个值(它可以是超过 2 个搜索值)时,我如何收缩 TermQuery。
  • 您是否尝试过@Val 的建议以使用TermQuery?我的建议是在编码之前编写和测试您的查询。我使用 SoapUI,但任何可以让你发送 http 请求的东西都可以(例如 curl 或浏览器插件)。只有在查询成功后,我才会将其转换为代码。
  • 不,我没有尝试在这种情况下使用 TermQuery,因为当它只需要一个字段时,我不知道如何使用它“OR”条件。能给个提示或例子吗?
  • 例如在“级别”字段中的某些对象中可以是“INFO”或“TRACE”。我需要用“INFO”或“TRACE”来攻击所有对象

标签: java elasticsearch


【解决方案1】:

通过使用keyword 类型,您的字段将不会被分析,并且需要与您的搜索字词完全匹配,包括区分大小写。如果将字段类型设置为text,则会对其进行分析,在默认分析器下,将使搜索不区分大小写。

此外,除非您的级别字段包含多个术语,否则您应该能够使用术语查询来搜索多个值。例如(DSL 格式):

GET _search
{
  "query": {
    "terms": {
      "level": [ "INFO", "TRACE" ]
    }
  }
}

【讨论】:

  • 我的字段“level”只能有一个值 - “INFO”或“TRACE”。但是在搜索请求(或查询)中,我想使用“级别”的几个含义来查找所有具有“TRACE”或“INFO”字段的“级别”对象。因此,在我的情况下,我使用“级别”请求(即一组)来查找所有具有“级别”“INFO”或“TRACE”的对象。
  • 所以,您的查询是正确的,但不是“级别”而是“级别”。我添加了 object(log) 的样子。
  • 在您的架构中,该字段称为“级别”,因此您将查询该字段。上面的术语查询将找到 level=INFO 或 TRACE 的所有结果。
  • 这有助于 bqb.filter(QueryBuilders.termsQuery("level", esLogRequest.getLevels()));
猜你喜欢
  • 1970-01-01
  • 2020-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-08
  • 2014-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多