Mattias Holmqvist
Mattias Holmqvist

Reputation: 832

No hits for nested analyzed field in elasticsearch

We want to search our nested field "texts" in multiple languages. However, when applying additional fields with different analyzers, we never get any hits.

Our configuration works for non-nested fields (such as "title" in the example below), so it seems to be related to the nesting somehow.

Mapping configuration:

{
"properties": {
"title": {
  "type": "string",
  "fields": {
    "en": {
      "type": "string",
      "analyzer": "english"
    }
  }
},
"texts": {
  "type": "nested",
  "value": {
    "type": "string",
    "fields": {
      "en": {
        "type": "string",
        "analyzer": "english"
      }
    }
  }
}
}
}

Test code:

TransportClient testClient = new TransportClient()
    .addTransportAddress(new InetSocketTransportAddress(hostname, port));

String test_index = "test_index";
IndicesExistsResponse indicesExistsResponse = testClient.admin().indices().exists(new IndicesExistsRequest(test_index))
    .actionGet();

if (indicesExistsResponse.isExists()) {
  testClient.admin().indices().prepareDelete(test_index).execute().actionGet();
}
testClient.admin().indices().prepareCreate(test_index).execute().actionGet();

String source = Streams.copyToStringFromClasspath("/index.json");
testClient.admin().indices()
    .preparePutMapping(test_index)
    .setType(ARTICLE_TYPE)
    .setSource(source).execute().actionGet();

Article article = new Article();
article.title = "Winter is coming";

Text text = new Text();
text.value = "The nicest summer shoes";
text.textId = UUID.randomUUID().toString();

article.texts = Collections.singletonList(text);

testClient.index(new IndexRequest(test_index, ARTICLE_TYPE, article.articleId)
    .source(objectMapper.writeValueAsBytes(article))
    .refresh(true)).actionGet();


SearchHits rawTitleSearchHits = testClient.prepareSearch(test_index)
    .setTypes(ARTICLE_TYPE)
    .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
    .setQuery(queryStringQuery("title:winter"))
    .execute().get().getHits();

SearchHits enTitleSearchHits = testClient.prepareSearch(test_index)
    .setTypes(ARTICLE_TYPE)
    .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
    .setQuery(queryStringQuery("title.en:winter"))
    .execute().get().getHits();

SearchHits rawTextSearchHits = testClient.prepareSearch(test_index)
    .setTypes(ARTICLE_TYPE)
    .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
    .setQuery(nestedQuery("texts", queryStringQuery("value:summer")))
    .execute().get().getHits();

SearchHits enTextSearchHits = testClient.prepareSearch(test_index)
    .setTypes(ARTICLE_TYPE)
    .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
    .setQuery(nestedQuery("texts", queryStringQuery("value.en:summer")))
    .execute().get().getHits();

SearchHits enTextSearchMatchHits = client.prepareSearch(test_index)
    .setTypes(ARTICLE_TYPE)
    .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
    .setQuery(nestedQuery("texts", matchQuery("value.en", "summer")))
    .execute().get().getHits();


assertThat(rawTextSearchHits.getTotalHits(), is(1L));
assertThat(rawTitleSearchHits.getTotalHits(), is(1L));
assertThat(enTitleSearchHits.getTotalHits(), is(1L));

// Fails. Why??
assertThat(enTextSearchHits.getTotalHits(), is(1L));

// Also fails. Why??
assertThat(enTextSearchMatchHits.getTotalHits(), is(1L));

Upvotes: 1

Views: 134

Answers (1)

Val
Val

Reputation: 217254

Your mapping for the nested field is missing the properties structure:

{
  "properties": {
    "title": {
      "type": "string",
      "fields": {
        "en": {
          "type": "string",
          "analyzer": "english"
        }
      }
    },
    "texts": {
      "type": "nested",
      "properties": {               <--- this structure is missing
        "value": {
          "type": "string",
          "fields": {
            "en": {
              "type": "string",
              "analyzer": "english"
            }
          }
        }
      }
    }
  }
}

After changing your mapping, you'll need to reindex your data.

UPDATE

Finally, in your query you need to use the full field path, i.e. texts.value.en instead of just value.en:

SearchHits enTextSearchHits = testClient.prepareSearch(test_index)
    .setTypes(ARTICLE_TYPE)
    .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
    .setQuery(nestedQuery("texts", queryStringQuery("texts.value.en:summer")))
    .execute().get().getHits();

SearchHits enTextSearchMatchHits = client.prepareSearch(test_index)
    .setTypes(ARTICLE_TYPE)
    .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
    .setQuery(nestedQuery("texts", matchQuery("texts.value.en", "summer")))
    .execute().get().getHits();

Upvotes: 2

Related Questions