Kareem
Kareem

Reputation: 61

How to perform Elastic Search Term Query with Analyzer and Two Parameters in Java API

I am new to Elastic Search, I am integrating it with MongoDB to index and search for data.

All these things are working fine and I build indexes using the following sample:

    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"
  }
}'

I am currently building a web service that will use Java API to do the required search queries.

I need to search within the built index with two identical values "term query". I know that for term queries we need to use analyzers to analyze text and be able to retrieve identical values.

I have tried several ways to build index and specify analyzers for certain fields but I couldn't. Also I have tried to do it from Java API level and it works fine but for only one filed, I couldn't be able to do that with two fields.

 SearchResponse r1 = client.prepareSearch("rootcause")
                    .setQuery(QueryBuilders.queryString("_id:" + rc.getRootCause_ID()).analyzer("snowball"))
                    .execute() 
                    .actionGet();

I am building a prototype to diagnose some devices failures,

I want to search by device model and the symptom entered by user. I have tried also the following code:

    SearchResponse response = client.prepareSearch("modelsymptom")
            .setQuery(QueryBuilders.queryString("model_id: " + "MO-1" + " AND " + "symptom: RC-4").analyzer("snowball"))
            .execute()
            .actionGet();

The retrieved results from the above query contains all documents with RC-4 or MO-1 and others which is not correct. This query should retrieve only one result.

What is better, to build an index with a prescribed analyzer or to do it from the Java API level?

From my understanding, I think it would be better to build analyzer with index for sure, but I don't know how so far.

Upvotes: 1

Views: 3411

Answers (2)

Pedro Lopez
Pedro Lopez

Reputation: 2276

I know that for term queries we need to use analyzers to analyze text and be able to retrieve identical values.

That is not correct.

While the full-text queries will analyse the query string before executing, the term-level queries operate on the exact terms that are stored in the inverted index.

When querying full-text fields, use the match query instead, which understands how the field has been analyzed.

Otherwise you will have the problems described here: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html

What is better, to build an index with a prescribed analyzer or to do it from the Java API level?

Either way, it depends on your specific scenario.

You can create an index with an analyser from Java if you want.

String analyser = "{...}";

CreateIndexRequestBuilder createIndexRequestBuilder = 
    client.admin().indices().prepareCreate("indexName");
createIndexRequestBuilder.setSettings(analyser);
createIndexRequestBuilder.execute().actionGet();

Where your analyser is something like:

{
    "analysis": 
    {    
        "analyzer": 
        {
            "my_analiser": 
            {
                "type": "english"
            }
        }
    }
}

But then you will need to create your own custom mapping and specify the analyser there.

If you do not specify your own mapping, when Elasticsearch detects a new string field in your documents, it automatically configures it as a full-text string field and analyses it with the standard analyser. That might be enough for you, but normally it is not, and you need to build your own mapping. You can do that from Java too.

// 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();

How to perfrom Elastic Search Term Query with Analyzer and Two Parameters in Java API

You can combine two term queries using a compound query like the boolean query:

Or user the terms query:

But according to what you have described here, if you really need to use analysed text, you are more likely to need the multi-match query, or a boolean query with two match queries.

MultiMatchQueryBuilder queryBuilder = 
   new MultiMatchQueryBuilder("foo", "fieldOne", "fieldTwo");
client.prepareSearch()
     .setIndices(index)
     .setQuery(queryBuilder)
     .execute().actionGet();

Or:

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();

Hope this helps.

Upvotes: 3

xeye
xeye

Reputation: 1256

You don't need any special analyzer, just use bool query with "must" and two terms. And "simple query" exists mostly to test queries manually, I would not use it in the code. Also always try your queries with REST API first.

{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "model": "XXXX",
          }
        },
        {
          "term": {
            "symptom": "YYYY" 
          }
        }
      ]
    }
  }
}

Upvotes: 1

Related Questions