3

Hi I'm a new to elastic nest API and I'm using nest 5.x. I'm currently developing some kind of advanced search page so when user doesn't check a criteria i don't have to include that filter on my query. I'm trying to combine 2 queries under must operator with object initializer approach using nest. How to achieve it? I'm following the example on [https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/bool-queries.html]

var secondSearchResponse = client.Search(new SearchRequest { Query = new TermQuery { Field = Field(p => p.Name), Value = "x" } && new TermQuery { Field = Field(p => p.Name), Value = "y" } });

But it doesnt work cause Field class doesnt accept type arguments.

I also tried to followed this approach from this topic [Nest Elastic - Building Dynamic Nested Query

here is my code

    public HttpResponseMessage GetSearchResult([FromUri] SearchModels queries)
    {
        try
        {
            ///
            string result = string.Empty;
            result += "queryfields + " + queries.queryfields == null ? string.Empty : queries.queryfields;
            result += "datefrom + " + queries.datefrom == null ? string.Empty : queries.datefrom;
            result += "dateto + " + queries.dateto == null ? string.Empty : queries.dateto;
            result += "emitentype + " + queries.emitentype == null ? string.Empty : queries.emitentype;

            QueryContainer andQuery = null;

            //List<QueryContainer> QueryContainers = new List<QueryContainer>();

            IDXNetAnnouncement record = new IDXNetAnnouncement
            {
                kode_emiten = queries.kodeemiten
            };

            #region keyword
            if (!string.IsNullOrEmpty(queries.queryfields))
            {
                var val = queries.queryfields;

                TermQuery tq = new TermQuery
                {
                    Field = queries.queryfields,
                    Value = val
                };

                if (andQuery == null)
                    andQuery = tq;
                else
                    andQuery &= tq;

                //QueryContainers.Add(tq);
            }
            #endregion keyword

            #region kodeemiten
            if (!string.IsNullOrEmpty(queries.kodeemiten))
            {
                var val = queries.kodeemiten;

                TermQuery tq = new TermQuery
                {
                    Name = "kode_emiten",
                    Field = record.kode_emiten,
                    Value = val
                };

                if (andQuery == null)
                    andQuery = tq;
                else
                    andQuery &= tq;

                //QueryContainers.Add(tq);
            }
            #endregion            

            #region date
            if (!string.IsNullOrEmpty(queries.datefrom) && !string.IsNullOrEmpty(queries.dateto))
            {
                DateRangeQuery dq = new DateRangeQuery();
                dq.Name = "tglpengumuman";
                dq.LessThanOrEqualTo = DateMath.Anchored(queries.dateto);
                dq.GreaterThanOrEqualTo = DateMath.Anchored(queries.datefrom);
                dq.Format = "dd/mm/yyyy";

                if (andQuery == null)
                    andQuery = dq;
                else
                    andQuery &= dq;

                //QueryContainers.Add(dq);
            }
            #endregion keyword

            var reqs = (ISearchResponse<IDXNetAnnouncement>)null;

            if (andQuery != null)
            {
                reqs = conn.client.Search<IDXNetAnnouncement>(s => s
                        .AllIndices()
                        .AllTypes()
                        .From(queries.indexfrom)
                        .Size(queries.pagesize)
                        .Query(q => q.Bool(qb => qb.Must(m => m.MatchAll() && andQuery))));
                //var json = conn.client.Serializer.SerializeToString(reqs.ApiCall.ResponseBodyInBytes);
            }
            else
            {
                reqs = conn.client.Search<IDXNetAnnouncement>(s => s
                       .AllIndices()
                       .AllTypes()
                       .From(queries.indexfrom)
                       .Size(queries.pagesize)
                       .Query(m => m.MatchAll()));
            }

            //var reqstring = Encoding.UTF8.GetString(conn.client.);
            var reslts = this.conn.client.Serializer.SerializeToString(reqs,SerializationFormatting.Indented);

            var resp = new HttpResponseMessage()
            {
                Content = new StringContent(reslts)
            };
            resp.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            return resp;
        }
        catch (Exception e)
        {
            var resp = new HttpResponseMessage()
            {
                Content = new StringContent(e.ToString())
            };
            resp.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            return resp;
        }
    }

But that returns zero result. How to achieve this? Thx anyway.

EDIT :

This is the params variabel definition. Its apoco model of search keywords

public class SearchModels
{
    public string queryfields { get; set; }
    public string datefrom { get; set; }
    public string dateto { get; set; }
    public string emitentype { get; set; }
    public string kodeemiten { get; set; }
    public string issuercode { get; set; }
    public int indexfrom { get; set; }
    public int pagesize { get; set; }

}

IDXNetAnnouncement is a poco model of search result. Its actualy a document type which is stored on the elastic server

public class IDXNetAnnouncement 
{
    public string perihalpengumuman { get; set; }
    public string attachments { get; set; }
    public string createddate { get; set; }
    public bool efekemiten_spei { get; set; }
    public string jmsxgroupid { get; set; }
    public string tglpengumuman { get; set; }
    public object errordescription { get; set; }
    public string ESversion { get; set; }
    public int oldfinalid { get; set; }
    public bool efekemiten_etf { get; set; }
    public object errorcode { get; set; }
    public string jenisemiten { get; set; }
    public int pkid { get; set; }
    public string judulpengumuman { get; set; }
    public string form_id { get; set; }
    public bool efekemiten_eba { get; set; }
    public string jenispengumuman { get; set; }
    public string nopengumuman { get; set; }
    public string kode_emiten { get; set; }
    public string divisi { get; set; }
    public string EStimestamp { get; set; }
    public bool efekemiten_obligasi { get; set; }
    public long finalid { get; set; }
    public bool efekemiten_saham { get; set; }
    public string kodedivisi { get; set; }
    public string SearchTerms
    {
        get
        {
            return string.Format("{0} {1} {2}", judulpengumuman, kode_emiten, nopengumuman);
        }
    }
}
si_yudist
  • 31
  • 1
  • 3

1 Answers1

2

But it doesnt work cause Field class doesnt accept type arguments.

You need to ensure that you include a using static directive for Nest.Infer i.e.

using static Nest.Infer;

with the rest of the using directives.

.Query(q => q.Bool(qb => qb.Must(m => m.MatchAll() && andQuery))));

No need to wrap in a Must(), just do

.Query(q => q.MatchAll() && andQuery)

which will wrap both queries in a bool query must clause. You also don't need to null check andQuery because NEST is smart enough to not combine the two queries if either or both are null.

if (!string.IsNullOrEmpty(queries.queryfields))
{
    var val = queries.queryfields;

    TermQuery tq = new TermQuery
    {
        Field = queries.queryfields,
        Value = val
    };

    if (andQuery == null)
        andQuery = tq;
    else
        andQuery &= tq;

    //QueryContainers.Add(tq);
}

NEST has the concept of conditionless queries so you don't need to check it queries.queryfields is null or empty, simply build the query and add it to andQuery. So it would become

var val = queries.queryfields;

andQuery &= new TermQuery
{
    Field = queries.queryfields,
    Value = val
};

Aside

All of the NEST documentation is generated from source code; you can trace back to the original source file by clicking on any edit link within the documentation. This will take you to a github page, such as this one for bool queries. From here, the document contains an important note that links back to the original source.

Russ Cam
  • 124,184
  • 33
  • 204
  • 266
  • Hi russ thanx for your advice regarding the null handling. Anyway i did have included the using static Nest.Infer; on my class. But still termquery not accepting type parameter. Is there any other using directive i should include? – si_yudist Jul 26 '17 at 10:58