ElasticSearch嵌套过滤器和聚合

时间:2015-12-19 14:19:14

标签: elasticsearch

所以我有这个映射:

"employee": {
  "properties": {
     "DaysOff": {
        "type": "nested",
        "properties": {
           "Date": {
              "type": "date",
              "format": "strict_date_optional_time||epoch_millis"
           },
           "Days": {
              "type": "double"
           },
           "ID": {
              "type": "long"
           }
        }
     }
  }
}

所以基本上一个员工可以休息几天。他们每天休息都存放在属性DaysOff下的数组中。 Days可能只有一天的一小部分,所以如果员工休息半天,那么0.5就可以了。

所以我有这个搜索:

{
   "size": 45,
   "filter": {
      "nested": {
         "path": "DaysOff",
         "filter": {
            "range": {
               "DaysOff.Date": {
                  "from": "now-2M",
                  "to": "now"
               }
            }
         }
      }  
   }
}

它带回了45个文件。哪个是对的。我现在无法弄清楚如何将聚合应用于这些文档,以便找回已经采取的所有日期的总和。

使用此resource我尝试了aggs,但没有得到正确的结果:

{
   "size": 45,
   "filter": {
      "nested": {
         "path": "DaysOff",
         "filter": {
            "range": {
               "DaysOff.Date": {
                  "from": "now-2M",
                  "to": "now"
               }
            }
         }
      }
   },
   "aggs": {
      "sum_docs": {
         "nested": {
            "path": "DaysOff"
         },
         "aggs": {
            "stepped_down": {
               "sum": {
                  "field": "DaysOff.Days"
               }
            }
         }
      }
   }
}

1 个答案:

答案 0 :(得分:2)

您需要nested documents POST employee { "mappings": { "emp_map": { "properties": { "DaysOff": { "type": "nested", "properties": { "Date": { "type": "date", "format": "strict_date_optional_time||epoch_millis" }, "Days": { "type": "double" }, "ID": { "type": "long" } } }, "name": { "type": "string" } } } } }, 才能获得正确的结果,来自文档

  

由于嵌套文档被索引为单独的文档,因此只能在嵌套查询的范围内访问它们,

我创建了像这样的索引

PUT employee/emp_map/1
{
  "name" : "messi",
  "DaysOff" : [
    {
     "Date" : "2015-11-01",
     "Days" : 1,
     "ID" : 11
    },
    {
     "Date" : "2014-11-01",
     "Days" : 2,
     "ID" : 11
    },
    {
     "Date" : "2015-12-01",
     "Days" : 0.5,
     "ID" : 11
    }
    ]
}

PUT employee/emp_map/2
{
  "name" : "ronaldo",
  "DaysOff" : [
    {
     "Date" : "2015-10-01",
     "Days" : 3,
     "ID" : 12
    },
    {
     "Date" : "2014-11-01",
     "Days" : 2,
     "ID" : 12
    },
    {
     "Date" : "2015-12-01",
     "Days" : 0.5,
     "ID" : 12
    }
    ]
}

PUT employee/emp_map/3
{
  "name" : "suarez",
  "DaysOff" : [
    {
     "Date" : "2015-11-01",
     "Days" : 4,
     "ID" : 13
    },
    {
     "Date" : "2015-11-09",
     "Days" : 2,
     "ID" : 13
    },
    {
     "Date" : "2015-12-01",
     "Days" : 1.5,
     "ID" : 13
    }
    ]
}

然后我索引了几个像这样的文件,

filter aggregation

这是我的查询,请注意nested aggregation中的GET employee/_search { "query": { "bool": { "filter": { "nested": { "path": "DaysOff", "query": { "range": { "DaysOff.Date": { "from": "now-2M", "to": "now" } } } } } } }, "aggs": { "emp_name": { "terms": { "field": "name", "size": 10 }, "aggs": { "nesting": { "nested": { "path": "DaysOff" }, "aggs": { "filter_date": { "filter": { "range": { "DaysOff.Date": { "from": "now-2M", "to": "now" } } }, "aggs": { "sum_taken_off_days": { "sum": { "field": "DaysOff.Days" } } } } } } } } }, "size": 0 } ,如果没有ES会给你所有日期的总和。

"aggregations": {
    "emp_name": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "messi",
          "doc_count": 1,
          "nesting": {
            "doc_count": 3,
            "filter_date": {
              "doc_count": 2,
              "sum_taken_off_days": {
                "value": 1.5
              }
            }
          }
        },
        {
          "key": "ronaldo",
          "doc_count": 1,
          "nesting": {
            "doc_count": 3,
            "filter_date": {
              "doc_count": 1,
              "sum_taken_off_days": {
                "value": 0.5
              }
            }
          }
        },
        {
          "key": "suarez",
          "doc_count": 1,
          "nesting": {
            "doc_count": 3,
            "filter_date": {
              "doc_count": 3,
              "sum_taken_off_days": {
                "value": 7.5
              }
            }
          }
        }
      ]
    }
  }

这是我得到的结果,

emp_name terms aggregation

P.S:这是每位员工,您可以删除import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.app.Fragment; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.SearchView; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.Toast; import entities.Order; import entities.User; public class HomeFragment extends Fragment implements TransAdapter.ClickListener { private RecyclerView rvTrans; private TransAdapter adapter; private MenuItem mSearchAction; private SearchView searchView; private ActionBar actionBar; private boolean isSearchOpened = false; private EditText etSearch; public HomeFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_home, container, false); rvTrans = (RecyclerView) view.findViewById(R.id.rv_transactions); rvTrans.setLayoutManager(new LinearLayoutManager(getActivity())); adapter = new TransAdapter(getActivity()); adapter.setClickListener(this); rvTrans.setAdapter(adapter); try { adapter.setOrderList(HomeActivity.backEnd.booksForSale()); } catch (Exception e) { Toast.makeText(getActivity().getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show(); } return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_search: handleMenuSearch(); break; } return super.onOptionsItemSelected(item); } @Override public void onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); mSearchAction = menu.findItem(R.id.action_search); searchView = (SearchView) MenuItemCompat.getActionView(mSearchAction); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { adapter.clearData(); try { adapter.setOrderList(HomeActivity.backEnd.bookGlobalSearch(query)); } catch (Exception e) { Toast.makeText(getActivity().getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show(); } return true; } @Override public boolean onQueryTextChange(String newText) { return false; } }); } @Override public void itemClicked(Order order) { Intent intent = new Intent(getActivity(), DetailsActivity.class); intent.putExtra("BOOK_PICTURE", order.getBookPicture()); intent.putExtra("BOOK_NAME", order.getBookName()); intent.putExtra("BOOK_AUTHOR", order.getAuthorName()); intent.putExtra("BOOK_GENRE", order.getGenre()); intent.putExtra("BOOK_PUBLISHING", order.getPublishingYear()); startActivity(intent); } private void handleMenuSearch() { actionBar = ((AppCompatActivity)getActivity()).getSupportActionBar(); //get the actionbar if(isSearchOpened){ //test if the search is open if(actionBar != null) { actionBar.setDisplayShowCustomEnabled(false); //disable a custom view inside the actionbar actionBar.setDisplayShowTitleEnabled(true); //show the title in the action bar } // hides the keyboard InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(etSearch.getWindowToken(), 0); isSearchOpened = false; } else { // open the search entry if(actionBar != null) { actionBar.setDisplayShowCustomEnabled(true); //enable it to display a // custom view in the action bar. // action.setCustomView(R.layout.search_bar);//add the custom view actionBar.setDisplayShowTitleEnabled(false); //hide the title } InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(etSearch, InputMethodManager.SHOW_IMPLICIT); isSearchOpened = true; } } } 以获得所有员工的总和。