Как выполнить Elastic Search Term Query с помощью Analyzer и двух параметров в Java API
Я новичок в Elastic Search, я интегрирую его с MongoDB для индексации и поиска данных.
Все это работает нормально, и я строю индексы, используя следующий пример:
curl -XPUT localhost:9200/test/newperson/1 -d '{
"type": "mongodb",
"mongodb": {
"servers": [
{ "host": "pc-4372", "port": 27017 }
],
"db": "newPerson",
"collection": "Person",
"options": { "secondary_read_preference": true },
"gridfs": false
},
"index": {
"name": "mongoIndex",
"type": "Person"
}
}'
В настоящее время я создаю веб-сервис, который будет использовать Java API для выполнения необходимых поисковых запросов.
Мне нужно искать во встроенном индексе с двумя одинаковыми значениями "запрос запроса". Я знаю, что для срочных запросов нам нужно использовать анализаторы для анализа текста и иметь возможность получать идентичные значения.
Я пробовал несколько способов построения индекса и определения анализаторов для определенных полей, но не смог. Также я попытался сделать это с уровня Java API, и он отлично работает, но только для одного поля я не смог сделать это с двумя полями.
SearchResponse r1 = client.prepareSearch("rootcause")
.setQuery(QueryBuilders.queryString("_id:" + rc.getRootCause_ID()).analyzer("snowball"))
.execute()
.actionGet();
Я создаю прототип для диагностики сбоев некоторых устройств,
Я хочу выполнить поиск по модели устройства и симптому, введенному пользователем. Я пробовал также следующий код:
SearchResponse response = client.prepareSearch("modelsymptom")
.setQuery(QueryBuilders.queryString("model_id: " + "MO-1" + " AND " + "symptom: RC-4").analyzer("snowball"))
.execute()
.actionGet();
Полученные результаты из вышеупомянутого запроса содержат все документы с RC-4 или MO-1 и другие, что является неправильным. Этот запрос должен получить только один результат.
Что лучше: создать индекс с помощью предписанного анализатора или сделать это на уровне Java API?
Насколько я понимаю, я думаю, что было бы лучше построить анализатор с индексом, но пока не знаю, как это сделать.
2 ответа
Я знаю, что для срочных запросов нам нужно использовать анализаторы для анализа текста и иметь возможность получать идентичные значения.
Это не правильно.
В то время как полнотекстовые запросы будут анализировать строку запроса перед выполнением, запросы на уровне терминов работают с точными терминами, которые хранятся в инвертированном индексе.
При запросе полнотекстовых полей используйте вместо этого запрос на совпадение, который понимает, как было проанализировано поле.
В противном случае у вас будут проблемы, описанные здесь: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html
Что лучше: создать индекс с помощью предписанного анализатора или сделать это на уровне Java API?
В любом случае, это зависит от вашего конкретного сценария.
Вы можете создать индекс с помощью анализатора из Java, если хотите.
String analyser = "{...}";
CreateIndexRequestBuilder createIndexRequestBuilder =
client.admin().indices().prepareCreate("indexName");
createIndexRequestBuilder.setSettings(analyser);
createIndexRequestBuilder.execute().actionGet();
Где ваш анализатор что-то вроде:
{
"analysis":
{
"analyzer":
{
"my_analiser":
{
"type": "english"
}
}
}
}
Но тогда вам нужно будет создать собственное отображение и указать там анализатор.
Если вы не укажете свое собственное отображение, когда Elasticsearch обнаружит новое строковое поле в ваших документах, он автоматически настроит его как полнотекстовое строковое поле и проанализирует его с помощью стандартного анализатора. Это может быть достаточно для вас, но обычно это не так, и вам нужно создать свое собственное отображение. Вы можете сделать это и с Java.
// Index (and mapping) do not exist
CreateIndexRequestBuilder createIndexRequestBuilder =
client.admin().indices().prepareCreate("indexName");
createIndexRequestBuilder.addMapping("typeName", mapping);
response = createIndexRequestBuilder.execute().actionGet();
// Index exists but not mapping
PutMappingRequestBuilder preparePutMappingBuilder =
client.admin().indices().preparePutMapping("indexName");
preparePutMappingBuilder.setSource(mapping).setType("typeName");
response = preparePutMappingBuilder.execute().actionGet();
Как выполнить Elastic Search Term Query с помощью Analyzer и двух параметров в Java API
Вы можете объединить два запроса с терминами, используя составной запрос, такой как логический запрос:
Ссылка: https://www.elastic.co/guide/en/elasticsearch/reference/current/compound-queries.html
Документация по Java: https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-compound-queries.html
Или используйте запрос условий:
Ссылка: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html
Документация по Java: https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-term-level-queries.html
Но согласно тому, что вы описали здесь, если вам действительно нужно использовать анализируемый текст, вам, скорее всего, понадобится запрос с несколькими совпадениями или логический запрос с двумя запросами на совпадение.
MultiMatchQueryBuilder queryBuilder =
new MultiMatchQueryBuilder("foo", "fieldOne", "fieldTwo");
client.prepareSearch()
.setIndices(index)
.setQuery(queryBuilder)
.execute().actionGet();
Или же:
QueryBuilder firstQueryBuilder = QueryBuilders.matchQuery("fieldOne", "foo");
QueryBuilder secondQueryBuilder = QueryBuilders.matchQuery("fieldTwo", "foo");
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(firstQueryBuilder);
boolQueryBuilder.must(secondQueryBuilder);
client.prepareSearch()
.setIndices(index)
.setQuery(queryBuilder)
.execute().actionGet();
Ссылка: https://www.elastic.co/guide/en/elasticsearch/reference/current/full-text-queries.html
Документация по Java: https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-full-text-queries.html
Надеюсь это поможет.
Вам не нужен специальный анализатор, просто используйте запрос bool с "must" и двумя терминами. А "простой запрос" существует в основном для проверки запросов вручную, я бы не использовал его в коде. Также всегда сначала пробуйте свои запросы с REST API.
{
"query": {
"bool": {
"must": [
{
"term": {
"model": "XXXX",
}
},
{
"term": {
"symptom": "YYYY"
}
}
]
}
}
}