【问题标题】:Troubles creating an index with custom analyzer using Jest使用 Jest 使用自定义分析器创建索引时遇到问题
【发布时间】:2015-01-12 23:28:22
【问题描述】:

Jest 为 elasticsearch 提供了出色的异步 API,我们发现它非常有用。然而,有时结果请求与我们预期的略有不同。

通常我们不在乎,因为一切正常,但在这种情况下却不是。

我想使用自定义 ngram 分析器创建索引。当我按照 elasticsearch rest API 文档执行此操作时,我在下面调用:

curl -XPUT 'localhost:9200/test' --data '
{
  "settings": {
    "number_of_shards": 3,
    "analysis": {
      "filter": {
        "keyword_search": {
          "type":     "edge_ngram",
          "min_gram": 3,
          "max_gram": 15
        }
      },
      "analyzer": {
        "keyword": {
          "type":      "custom",
          "tokenizer": "whitespace",
          "filter": [
            "lowercase",
            "keyword_search"
          ]
        }
      }
    }
  }
}'

然后我确认分析器配置正确:

curl -XGET 'localhost:9200/test/_analyze?analyzer=keyword&text=Expecting many tokens

作为回应,我收到了多个令牌,例如 expexpeexpec 等。

现在使用 Jest 客户端,我将配置 json 放到我的类路径上的一个文件中,内容与上面的 PUT 请求的正文完全相同。我执行这样构造的 Jest 动作:

new CreateIndex.Builder(name)
            .settings(
                    ImmutableSettings.builder()
                            .loadFromClasspath(
                                    "settings.json"
                            ).build().getAsMap()
            ).build();

结果

  • Primo - 使用 tcpdump 检查实际发布到 elasticsearch 的内容是(打印得很漂亮):

    {
      "settings.analysis.filter.keyword_search.max_gram": "15",
      "settings.analysis.filter.keyword_search.min_gram": "3",
      "settings.analysis.analyzer.keyword.tokenizer": "whitespace",
      "settings.analysis.filter.keyword_search.type": "edge_ngram",
      "settings.number_of_shards": "3",
      "settings.analysis.analyzer.keyword.filter.0": "lowercase",
      "settings.analysis.analyzer.keyword.filter.1": "keyword_search",
      "settings.analysis.analyzer.keyword.type": "custom"
    }
    
  • Secundo - 生成的索引设置为:

    {
      "test": {
        "settings": {
          "index": {
            "settings": {
              "analysis": {
                "filter": {
                  "keyword_search": {
                    "type": "edge_ngram",
                    "min_gram": "3",
                    "max_gram": "15"
                  }
                },
                "analyzer": {
                  "keyword": {
                    "filter": [
                      "lowercase",
                      "keyword_search"
                    ],
                    "type": "custom",
                    "tokenizer": "whitespace"
                  }
                }
              },
              "number_of_shards": "3"   <-- the only difference from the one created with rest call
            },
            "number_of_shards": "3",
            "number_of_replicas": "0",
            "version": {"created": "1030499"},
            "uuid": "Glqf6FMuTWG5EH2jarVRWA"
          }
        }
      }
    }
    
  • Tertio - 用 curl -XGET 'localhost:9200/test/_analyze?analyzer=keyword&amp;text=Expecting many tokens 检查分析器我只得到一个令牌!

问题1.是什么原因导致Jest没有发布我的原始设置json,而是一些处理了?

问题 2。 为什么 Jest 生成的设置不起作用?

【问题讨论】:

    标签: java elasticsearch elasticsearch-jest


    【解决方案1】:

    很高兴您发现 Jest 很有用,请在下面查看我的回答。

    问题 1. Jest 不发布我的原件的原因是什么 设置 json,但有些处理了一个?

    这不是 Jest,而是 Elasticsearch 的 ImmutableSettings 这样做,请参阅:

        Map test = ImmutableSettings.builder()
                .loadFromSource("{\n" +
                        "  \"settings\": {\n" +
                        "    \"number_of_shards\": 3,\n" +
                        "    \"analysis\": {\n" +
                        "      \"filter\": {\n" +
                        "        \"keyword_search\": {\n" +
                        "          \"type\":     \"edge_ngram\",\n" +
                        "          \"min_gram\": 3,\n" +
                        "          \"max_gram\": 15\n" +
                        "        }\n" +
                        "      },\n" +
                        "      \"analyzer\": {\n" +
                        "        \"keyword\": {\n" +
                        "          \"type\":      \"custom\",\n" +
                        "          \"tokenizer\": \"whitespace\",\n" +
                        "          \"filter\": [\n" +
                        "            \"lowercase\",\n" +
                        "            \"keyword_search\"\n" +
                        "          ]\n" +
                        "        }\n" +
                        "      }\n" +
                        "    }\n" +
                        "  }\n" +
                        "}").build().getAsMap();
        System.out.println("test = " + test);
    

    输出:

    test = {
        settings.analysis.filter.keyword_search.type=edge_ngram,
        settings.number_of_shards=3,
        settings.analysis.analyzer.keyword.filter.0=lowercase,
        settings.analysis.analyzer.keyword.filter.1=keyword_search,
        settings.analysis.analyzer.keyword.type=custom,
        settings.analysis.analyzer.keyword.tokenizer=whitespace,
        settings.analysis.filter.keyword_search.max_gram=15,
        settings.analysis.filter.keyword_search.min_gram=3
    }
    

    问题 2。 为什么 Jest 生成的设置不起作用?

    因为您对设置 JSON/map 的使用不是预期的情况。我创建了这个测试来重现你的情况(它有点长,但请耐心等待):

        @Test
        public void createIndexTemp() throws IOException {
            String index = "so_q_26949195";
    
            String settingsAsString = "{\n" +
                    "  \"settings\": {\n" +
                    "    \"number_of_shards\": 3,\n" +
                    "    \"analysis\": {\n" +
                    "      \"filter\": {\n" +
                    "        \"keyword_search\": {\n" +
                    "          \"type\":     \"edge_ngram\",\n" +
                    "          \"min_gram\": 3,\n" +
                    "          \"max_gram\": 15\n" +
                    "        }\n" +
                    "      },\n" +
                    "      \"analyzer\": {\n" +
                    "        \"keyword\": {\n" +
                    "          \"type\":      \"custom\",\n" +
                    "          \"tokenizer\": \"whitespace\",\n" +
                    "          \"filter\": [\n" +
                    "            \"lowercase\",\n" +
                    "            \"keyword_search\"\n" +
                    "          ]\n" +
                    "        }\n" +
                    "      }\n" +
                    "    }\n" +
                    "  }\n" +
                    "}";
            Map settingsAsMap = ImmutableSettings.builder()
                    .loadFromSource(settingsAsString).build().getAsMap();
    
            CreateIndex createIndex = new CreateIndex.Builder(index)
                    .settings(settingsAsString)
                    .build();
    
            JestResult result = client.execute(createIndex);
            assertTrue(result.getErrorMessage(), result.isSucceeded());
    
            GetSettings getSettings = new GetSettings.Builder().addIndex(index).build();
            result = client.execute(getSettings);
            assertTrue(result.getErrorMessage(), result.isSucceeded());
            System.out.println("SETTINGS SENT AS STRING settingsResponse = " + result.getJsonString());
    
            Analyze analyze = new Analyze.Builder()
                    .index(index)
                    .analyzer("keyword")
                    .source("Expecting many tokens")
                    .build();
            result = client.execute(analyze);
            assertTrue(result.getErrorMessage(), result.isSucceeded());
            Integer actualTokens = result.getJsonObject().getAsJsonArray("tokens").size();
            assertTrue("Expected multiple tokens but got " + actualTokens, actualTokens > 1);
    
            analyze = new Analyze.Builder()
                    .analyzer("keyword")
                    .source("Expecting single token")
                    .build();
            result = client.execute(analyze);
            assertTrue(result.getErrorMessage(), result.isSucceeded());
            actualTokens = result.getJsonObject().getAsJsonArray("tokens").size();
            assertTrue("Expected single token but got " + actualTokens, actualTokens == 1);
    
            admin().indices().delete(new DeleteIndexRequest(index)).actionGet();
    
            createIndex = new CreateIndex.Builder(index)
                    .settings(settingsAsMap)
                    .build();
    
            result = client.execute(createIndex);
            assertTrue(result.getErrorMessage(), result.isSucceeded());
    
            getSettings = new GetSettings.Builder().addIndex(index).build();
            result = client.execute(getSettings);
            assertTrue(result.getErrorMessage(), result.isSucceeded());
            System.out.println("SETTINGS AS MAP settingsResponse = " + result.getJsonString());
    
            analyze = new Analyze.Builder()
                    .index(index)
                    .analyzer("keyword")
                    .source("Expecting many tokens")
                    .build();
            result = client.execute(analyze);
            assertTrue(result.getErrorMessage(), result.isSucceeded());
            actualTokens = result.getJsonObject().getAsJsonArray("tokens").size();
            assertTrue("Expected multiple tokens but got " + actualTokens, actualTokens > 1);
        }
    

    当您运行它时,您会看到使用 settingsAsMap 的情况下,实际设置完全错误(settings 包含另一个 settings,这是您的 JSON,但它们应该已经合并),所以分析失败。

    为什么这不是预期用途?

    仅仅是因为这就是 Elasticsearch 在这种情况下的行为方式。如果设置数据是flattened(默认情况下由ImmutableSettings 类完成),那么它不应该有顶级元素settings,但如果数据可以有相同的顶级元素没有展平(这就是 settingsAsString 的测试用例有效的原因)。

    tl;博士:

    您的设置 JSON 不应包含顶级“设置”元素(如果您通过 ImmutableSettings 运行它)。

    【讨论】:

    • 感谢您的努力回答我的问题,它一定需要一段时间!我采纳了您的建议,删除了顶部设置元素,效果很好。
    • 没有问题!请记住,您可以将原始字符串用作 source
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-28
    • 2015-10-21
    • 2023-03-25
    • 2022-01-01
    • 2011-03-29
    • 2013-03-07
    相关资源
    最近更新 更多