Is there any option in elasticsearch to use aggregation for multiple fields and get total count ?.
My query is
"SELECT COUNT(*), currency,type,status,channel FROM temp_index WHERE country='SG' and received_time=now/d group by currency,type,status,channel
Trying to implement the above in Java code using RestHighLevelClient , any suggestions or assistance will be helpful.
Currently we are using COUNT API
List<Object> dashboardsDataTotal = new ArrayList<>();
String[] channelList = { "test1", "test2", "test3", "test4", "test5", "test6" };
String[] currencyList = { "SGD", "HKD", "USD", "INR", "IDR", "PHP", "CNY" };
String[] statusList = { "COMPLETED", "FAILED", "PENDING", "FUTUREPROCESSINGDATE" };
String[] paymentTypeList = { "type1", "type2" };
String[] countryList = { "SG", "HK"};
CountRequest countRequest = new CountRequest(INDEX);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
try {
for (String country : countryAccess) { // per country
Map<String, Object> dashboardsDataPerCountry = new HashMap<>();
for (String channel : channelList) { // per channel
Map<String, Object> channelStore = new HashMap<>();
for (String paymentType : paymentTypeList) {
List<Object> paymentTypeStore = new ArrayList<>();
for (String currency : currencyList) {
Map<String, Object> currencyStore = new HashMap<>();
int receivedCount = 0;
for (String latestStatus : statusList) {
BoolQueryBuilder searchBoolQuery = QueryBuilders.boolQuery();
searchBoolQuery
.must(QueryBuilders.termQuery("channel", channel.toLowerCase()));
searchBoolQuery
.must(QueryBuilders.termQuery("currency", currency.toLowerCase()));
searchBoolQuery.must(QueryBuilders.matchPhraseQuery("source_country",
country.toLowerCase()));
if ("FUTUREPROCESSINGDATE".equalsIgnoreCase(latestStatus)) {
searchBoolQuery.must(
QueryBuilders.rangeQuery("processing_date").gt(currentDateS).timeZone(getTimeZone(country)));
}
else {
searchBoolQuery.must(QueryBuilders.termQuery("txn_latest_status",
latestStatus.toLowerCase()));
}
searchBoolQuery.must(
QueryBuilders.termQuery("paymentType", paymentType.toLowerCase()));
searchBoolQuery.must(QueryBuilders.rangeQuery("received_time").gte(currentDateS)
.lte(currentDateS).timeZone(getTimeZone(country)));
searchSourceBuilder.query(searchBoolQuery);
countRequest.source(searchSourceBuilder);
// try {
CountResponse countResponse = restHighLevelClient.count(countRequest,
RequestOptions.DEFAULT);
if (!latestStatus.equals("FUTUREPROCESSINGDATE")) {
receivedCount += countResponse.getCount();
}
currencyStore.put(latestStatus, countResponse.getCount());
}
currencyStore.put("RECEIVED", receivedCount); // received = pending + completed + failed
currencyStore.put("currency", currency);
paymentTypeStore.add(currencyStore);
} // per currency end
channelStore.put(paymentType, paymentTypeStore);
} // paymentType end
dashboardsDataPerCountry.put(channel, channelStore);
dashboardsDataPerCountry.put("country", country);
} // per channel end
dashboardsDataTotal.add(dashboardsDataPerCountry);
} // per country end
restHighLevelClient.close();
}
Appreciate if someone can provide a better solution to the above.
Made use of CompositeAggregationBuilder and got the aggregated results
CompositeAggregationBuilder compositeAgg = new CompositeAggregationBuilder("aggregate_buckets", sources);
searchSourceBuilder.aggregation(compositeAgg);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
Aggregations aggregations = searchResponse.getAggregations();
ParsedComposite parsedComposite = aggregations.get("aggregate_buckets");
List<ParsedBucket> list = parsedComposite.getBuckets();
Map<String,Object> data = new HashMap<>();
for (ParsedBucket parsedBucket : list) {
data.clear();
for (Map.Entry<String, Object> m : parsedBucket.getKey().entrySet()) {
data.put(m.getKey(), m.getValue());
}
data.put("count", parsedBucket.getDocCount());
System.out.println(data);
}
Related
public Predicate get_data(String field, String method, String value) throws Exception
{
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<student> cq = cb.createQuery(student.class);
Root<student> s = cq.from(student.class);
Predicate selected_field = null;
number = new BigDecimal(value);
if(method.equals("greaterThan") || method.equals("greaterThanOrEqualTo") ||
method.equals("lessThan") || method.equals("lessThanOrEqualTo"))
{
Method cbMethod = cb.getClass().getMethod(method,Expression.class,Comparable.class);
selected_field = (Predicate) cbMethod.invoke(cb,s.get(field), number);
}
else if(method.equals("eq"))
{
method = "equal";
Method cbMethod = cb.getClass().getMethod(method,Expression.class,Object.class);
selected_field = (Predicate) cbMethod.invoke(cb,s.get(field),number);
}
return selected_field;
}
public List<student> get(String search) throws Exception
{
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<student> cq = cb.createQuery(student.class);
Root<student> s = cq.from(student.class);
List<Predicate> selected_field = new ArrayList<>();
System.out.println(search);
List<String> query = Arrays.asList(search.split("And",0));
System.out.println(query.size());
List<String> fields = new ArrayList<>();
List<String> values = new ArrayList<>();
List<String> method = new ArrayList<>();
for (String str : query)
{
List<String> s1 = null;
int index_lt = str.indexOf('<');
int index_gt = str.indexOf('>');
int index_eq = str.indexOf('=');
if(index_lt != -1)
{
s1 = Arrays.asList(str.split("<",0));
method.add("lessThan");
}
else if(index_gt != -1)
{
s1 = Arrays.asList(str.split(">",0));
method.add("greaterThan");
}
else if(index_eq != -1)
{
s1 = Arrays.asList(str.split("=",0));
method.add("equal");
}
System.out.println("S1"+s1);
fields.add("student_"+s1.get(0));
values.add(s1.get(1));
}
for(int i = 0 ; i < fields.size() ; i++)
{
selected_field.add(get_data(fields.get(i),method.get(i),values.get(i)));
}
cq.where(cb.and(selected_field.toArray(new Predicate[] {})));
cq.where(predicatesarr);
System.out.println("where ends");
TypedQuery<student> search_query = em.createQuery(cq);
return search_query.getResultList();
}
when I am sending this http://localhost:8080/?search=rollNo>13 then it is giving me this error.
org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: 'generatedAlias1.student_rollNo' [select generatedAlias0 from io.poc_task1.poc_task1.student as generatedAlias0 where generatedAlias1.student_rollNo>13]
Can anyone help me with this? Thanks in advance.
I have below json and need to update elements, below code works for elements in top level, How can I extend this to work it inside another inner level (object).
Json:
{
"name": George,
"version": "2.0",
"reqParams": {
"headerId": "this needs to be updated",
"queue": "draft",
}
}
In below code I am passing below
eg.
keyPath = "headerId"
updateText = "123456"
jsonText = above json
Code :
public String updateValue(String keyPath, String updateText, String jsonText) {
String[] keys = keyPath.split("/");
JsonParser jsonParser = new JsonParser();
JsonObject jsonObject = (JsonObject) jsonParser.parse(jsonText);
JsonObject returnVal = jsonObject; // This holds the ref to target json object
JsonPrimitive jp = new JsonPrimitive(updateText);
String finalKey = keys[keys.length - 1];
for(String key : keys)
{
if (jsonObject.get(key) != null && jsonObject.get(key).isJsonObject())
{
jsonObject = (JsonObject)jsonObject.get(key);
}
}
jsonObject.remove(finalKey);
jsonObject.add(finalKey, jp);
return returnVal.toString();
}
Code
Expected out put json:
{
"name": George,
"version": "2.0",
"reqParams": {
"headerId": "123456",
"queue": "draft",
}
}
Actual reult:
{
"name": George,
"version": "2.0",
"reqParams": {
"headerId": "this needs to be updated",
"queue": "draft",
},
"headerId": "123456",
}
Pass keyPath as "reqParams/headerId" because headerId is inside reqParams and not at root level of JSON.
Updated code slightly and pass parameters as suggested by #Smile answer
keyPath : reqParams/headerId
someId (if exist in root level)
Code :
public String updateValue(String keyPath, String updateText, String jsonText) {
String[] keys = keyPath.split("/");
JsonParser jsonParser = new JsonParser();
JsonObject jsonObject = (JsonObject) jsonParser.parse(jsonText);
JsonObject returnVal = jsonObject; // This holds the ref to target json object
JsonPrimitive jp = new JsonPrimitive(updateText);
String finalKey = keys[keys.length - 1];
for (String key : keys) {
if (jsonObject.get(key) != null && jsonObject.get(key).isJsonObject()) {
jsonObject = (JsonObject) jsonObject.get(key);
jsonObject.remove(finalKey);
jsonObject.add(finalKey, jp);
return returnVal.toString();
} else if (jsonObject.get(finalKey) == null) {
return returnVal.toString();
}
}
jsonObject.remove(finalKey);
jsonObject.add(finalKey, jp);
return returnVal.toString();
}
I can create with enhanced for loop and with map's computeIfAbsent as below.
String [][] students = {{"David","50"},{"Sherif","70"},{"Bhavya","85"},{"Bhavya","95"}};
Map<String, List<Integer>> map = new HashMap<String, List<Integer>>();
for(String student[] : students) {
map.computeIfAbsent(student[0], (k)->new ArrayList<Integer>()).add(Integer.parseInt(student[1]));
}
Is there any way I can use stream with collectors api to build map as above?
Map<String, List<Integer>> m = Arrays.stream(students)
.collect(Collectors.?);
Try this out.
String[][] students = { { "David", "50" }, { "Sherif", "70" }, { "Bhavya", "85" }, { "Bhavya", "95" } };
Map<String, List<Integer>> studentsByName = Stream.of(students).collect(Collectors.groupingBy(kv -> kv[0],
Collectors.mapping(kv -> Integer.valueOf(kv[1]), Collectors.toList())));
System.out.println(studentsByName);
You can try like this
map = Arrays.stream(students)
.map(array->new Pair<String,Integer>(array[0],Integer.valueOf(array[1])))
.collect(Collectors.groupingBy(p->p.getKey(), Collectors.mapping(p->p.getValue(),
Collectors.toList())));
Using groupingBy:
Arrays.stream(students)
.map(a -> new AbstractMap.SimpleEntry<>(a[0], Integer.valueOf(a[1])))
.collect(groupingBy(AbstractMap.SimpleEntry::getKey,
mapping(AbstractMap.SimpleEntry::getValue,
toList())));
Using toMap:
Arrays.stream(students)
.map(a -> new AbstractMap.SimpleEntry<>(a[0], Integer.valueOf(a[1])))
.collect(toMap(AbstractMap.SimpleEntry::getKey,
k -> new ArrayList<>(Collections.singletonList(k.getValue())),
(left, right) -> {left.addAll(right);return left;}));
I am very much new to Lucene.net and though I am not able to achieve basic functionality i.e. Not in.
My requirement is to search "road?construction" without "Works" word.
e.g.
Main Road Construction Works -- Invalid
Road Construction And Maintenance Services -- Valid (Doesn't contains word Works)
Please refer my code below.
string searchQuery = "\"road?construction\"*";
BooleanQuery query2 = new BooleanQuery();
Query query;
try
{
query = parser.Parse(searchQuery.Trim());
}
catch (ParseException)
{
query = parser.Parse(QueryParser.Escape(searchQuery.Trim()));
}
query2.Add(query,Occur.SHOULD);
query2.Add(new BooleanClause(new TermQuery (new Term("Name", "Works")), Occur.MUST_NOT));
This still gets both above mentioned record in to search result. I wish to cut invalid record(first).
Here is the result query generated in backend.
Please suggest workaround.
Thanks in advanced.
Not sure why your putting wildcard characters into the phrase. If you're looking for "road construction" then that's all you need. If you are looking to allow some variations then maybe a "slop phrase" is what you need ie. "road construction"~2. The number part allows for n "operations" like n additional words inbetween.
Here's a set of tests that show your examples (TestExpr2, TestExpr3) and some working variations (TestExpr1 and TestQuery).
Hope this helps
[TestClass]
public class UnitTest7
{
[TestMethod]
public void TestExpr1()
{
TestExpr("\"road construction\" -works");
}
[TestMethod]
public void TestExpr2()
{
TestExpr("\"road?construction\"* -works");
}
[TestMethod]
public void TestExpr3()
{
TestExpr(QueryParser.Escape("\"road?construction\"* -works"));
}
private void TestExpr(string expr)
{
var writer = CreateIndex();
Add(writer, "Main Road Construction Works");
Add(writer, "Road Construction And Maintenance Services");
writer.Flush(true, true, true);
var searcher = new IndexSearcher(writer.GetReader());
var result = Search(searcher, expr);
Assert.AreEqual(1, result.Count);
Assert.IsTrue(result.Contains("Road Construction And Maintenance Services"));
writer.Dispose();
}
[TestMethod]
public void TestQuery()
{
var writer = CreateIndex();
Add(writer, "Main Road Construction Works");
Add(writer, "Road Construction And Maintenance Services");
writer.Flush(true, true, true);
var searcher = new IndexSearcher(writer.GetReader());
var query = new BooleanQuery();
var p = new PhraseQuery();
p.Add(new Term("name", "road"));
p.Add(new Term("name", "construction"));
query.Add(p, Occur.MUST);
query.Add(new TermQuery(new Term("name", "works")), Occur.MUST_NOT);
var result = Search(searcher, query);
Assert.AreEqual(1, result.Count);
Assert.IsTrue(result.Contains("Road Construction And Maintenance Services"));
writer.Dispose();
}
private List<string> Search(IndexSearcher searcher, string expr)
{
var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30);
var queryParser = new QueryParser(Lucene.Net.Util.Version.LUCENE_30, "name", analyzer);
var query = queryParser.Parse(expr);
return Search(searcher, query);
}
private List<string> Search(IndexSearcher searcher, Query query)
{
var collector = TopScoreDocCollector.Create(10, true);
searcher.Search(query, collector);
var result = new List<string>();
var matches = collector.TopDocs().ScoreDocs;
foreach (var item in matches)
{
var id = item.Doc;
var doc = searcher.Doc(id);
result.Add(doc.GetField("name").StringValue);
}
return result;
}
IndexWriter CreateIndex()
{
var directory = new RAMDirectory();
var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30);
var writer = new IndexWriter(directory, analyzer, new IndexWriter.MaxFieldLength(1000));
return writer;
}
void Add(IndexWriter writer, string text)
{
var document = new Document();
document.Add(new Field("name", text, Field.Store.YES, Field.Index.ANALYZED));
writer.AddDocument(document);
}
}
I m new to Elasticsearch 2.1.1, I want to Ask you how to fetch records from index using Suggest and convert it to DataTable. I've installed Nest NuGet Packages and all in my project.
I have this block of code which I want it from Elasticsearch in DataTable format
curl -X POST 'localhost:9200/music/_suggest?pretty' -d '{
"song-suggest" : {
"text" : "n",
"completion" : {
"field" : "suggest"
}
}
}'
I've some blocks of code it should fulfill your requirements.
As you said you are new to Elasticsearch, so I shwoing you first how to initialize connection.
var settings = new ConnectionSettings(new Uri("http://localhost:9200"));
var clientElasticSearchNet = new ElasticsearchClient(settings);
then use
var ElasticSearchNetQuery = new { music = new { "n", completion = new { field = "name_suggest" } } };
ElasticsearchResponse<string> result = clientElasticSearchNet.Suggest<string>("music", ElasticSearchNetQuery);
JObject json = JObject.Parse(result.Response.ToString());
var hitsCount = ((Newtonsoft.Json.Linq.JContainer)(json["music"].First["options"])).Count;
DataTable dtEsReponnse = new DataTable();
for (int i = 0; i < hitsCount; i++)
{
dtEsReponnse = ConvertJSONToDataTable(json["music"].First["options"][i].ToString());
}
I have created one function which will return Datatable.
protected DataTable ConvertJSONToDataTable(string jsonString)
{
string[] jsonParts = Regex.Split(jsonString.Replace("[", "").Replace("]", ""), "},{");
List<string> dtColumns = new List<string>();
foreach (string jp in jsonParts)
{
string[] propData = Regex.Split(jp.Replace("{", "").Replace("}", ""), ",");
foreach (string rowData in propData)
{
try
{
int idx = rowData.IndexOf(":");
string n = rowData.Substring(0, idx - 1);
string v = rowData.Substring(idx + 1);
if (!dtColumns.Contains(n))
{
dtColumns.Add(n.Replace("\"", ""));
}
}
catch (Exception ex)
{
throw new Exception(string.Format("Error Column Name : {0}", rowData));
}
}
break;
}
foreach (string c in dtColumns)
{
if (!dt.Columns.Contains(c.ToString().Replace("\r\n", "").Trim())) {
dt.Columns.Add(c.ToString().Replace("\r\n", "").Trim());
}
}
foreach (string jp in jsonParts)
{
string[] propData = Regex.Split(jp.Replace("{", "").Replace("}", ""), ",");
DataRow nr = dt.NewRow();
foreach (string rowData in propData)
{
try
{
int idx = rowData.IndexOf(":");
string n = rowData.Substring(0, idx - 1).Replace("\"", "").Replace("\r\n", "").Trim(); //replaced
string v = rowData.Substring(idx + 1).Replace("\"", "");
nr[n] = v;
}
catch (Exception ex)
{
continue;
}
}
dt.Rows.Add(nr);
}
return dt;
}
Is this code you looking for?