2016-08-23 168 views
2

最近我开始使用ElasticSearch,我打算坚持使用它来获得我正在构建的服务。elasticsearch中的聚合和排序

我基本上有以下几种类型:

  • 搜索
  • 提供报价

每个搜索的

  • 价格都有一套信息加上SID(搜索ID),每个优惠都有一个OID(优惠ID)加上搜索的SID和一组价格。

    我会异步接收数据,以避免使用_update,而不是在报价中包含价格数组并更新它,每个价格都存储在一个单独的文档中,并包含搜索ID,商品ID和价格本身。

    我向:

    • 过滤器由SID
    • 骨料由OID
    • 按价格排序骨料

    我怎么能做到这一点?任何提示?我在阅读文档了解如何聚集,但我完全不知道该:(

    编辑:

    在这里有一个例子集

    搜索(UUID是SID)

    { 
        'sid_1': { 'q': 'bread', 'sid': 'sid_1' }, 
        'sid_2': { 'q': 'milk', 'sid': 'sid_2' }, 
        'sid_3': { 'q': 'donuts', 'sid': 'sid_3' } 
    } 
    

    优惠(UUID是SID#OID)

    { 
        'sid_1#kamut-bread': { 'name': 'kamut bread', 'sid': 'sid_1', 'oid': 'kamut-bread' }, 
        'sid_1#chocolate-bread': { 'name': 'chocolate bread', 'sid': 'sid_1', 'oid': 'chocolate-bread' }, 
        'sid_1#plastic-bread': { 'name': 'plastic bread', 'sid': 'sid_1', 'oid': 'plastic-bread' }, 
        'sid_2#soya-milk': { 'name': 'soya milk', 'sid': 'sid_2', 'oid': 'soya-milk' }, 
        'sid_2#vaccine-milk': { 'name': 'vaccine milk', 'sid': 'sid_2', 'oid': 'vaccine-milk' }, 
        'sid_2#milk': { 'name': 'milk', 'sid': 'sid_2', 'oid': 'milk' }, 
        'sid_3#cream-donuts': { 'name': 'cream donuts', 'sid': 'sid_3', 'oid': 'cream-donuts' }, 
        'sid_3#chocolate-donuts': { 'name': 'chocolate donuts', 'sid': 'sid_3', 'oid': 'chocolate-donuts' }, 
        'sid_3#square-donuts': { 'name': 'square donuts', 'sid': 'sid_3', 'oid': 'square-donuts' } 
    } 
    

    OFFERS_PRICES(UUID是SID#OID#合伙人)

    { 
        'sid_1#kamut-bread#amazon': { 'partner': 'amazon', 'sid': 'sid_1', 'oid': 'kamut-bread', 'price': 10.1, 'fees': { 'mastercard': 1, 'visa': 1, 'paypal': 2, 'wiretransfer': 0 } }, 
        'sid_1#kamut-bread#store2': { 'partner': 'store2', 'sid': 'sid_1', 'oid': 'kamut-bread', 'price': 11.1, 'fees': { 'mastercard': 1, 'visa': 1, 'paypal': 2, 'wiretransfer': 0 } }, 
        'sid_1#kamut-bread#store3': { 'partner': 'store3', 'sid': 'sid_1', 'oid': 'kamut-bread', 'price': 10.4, 'fees': { 'mastercard': 1, 'visa': 1, 'paypal': 2, 'wiretransfer': 0 } }, 
        'sid_1#kamut-bread#store4': { 'partner': 'store4', 'sid': 'sid_1', 'oid': 'kamut-bread', 'price': 10.8, 'fees': { 'mastercard': 1, 'visa': 1, 'paypal': 2, 'wiretransfer': 0 } }, 
        'sid_1#chocolate-bread#amazon': { 'partner': 'amazon', 'sid': 'sid_1', 'oid': 'chocolate-bread', 'price': 7.1, 'fees': { 'mastercard': 1, 'visa': 1, 'paypal': 2, 'wiretransfer': 0 } }, 
        'sid_1#chocolate-bread#store2': { 'partner': 'store2', 'sid': 'sid_1', 'oid': 'chocolate-bread', 'price': 7.1, 'fees': { 'mastercard': 1, 'visa': 1, 'paypal': 2, 'wiretransfer': 0 } }, 
        'sid_1#chocolate-bread#store3': { 'partner': 'store3', 'sid': 'sid_1', 'oid': 'chocolate-bread', 'price': 8.4, 'fees': { 'mastercard': 1, 'visa': 1, 'paypal': 2, 'wiretransfer': 0 } }, 
        'sid_1#chocolate-bread#store4': { 'partner': 'store4', 'sid': 'sid_1', 'oid': 'chocolate-bread', 'price': 9.8, 'fees': { 'mastercard': 1, 'visa': 1, 'paypal': 2, 'wiretransfer': 0 } }, 
        'sid_1#plastic-bread#amazon': { 'partner': 'amazon', 'sid': 'sid_1', 'oid': 'plastic-bread', 'price': 70.1, 'fees': { 'mastercard': 1, 'visa': 1, 'paypal': 2, 'wiretransfer': 0 } }, 
        'sid_1#plastic-bread#store2': { 'partner': 'store2', 'sid': 'sid_1', 'oid': 'plastic-bread', 'price': 75.1, 'fees': { 'mastercard': 1, 'visa': 1, 'paypal': 2, 'wiretransfer': 0 } }, 
        'sid_1#plastic-bread#store3': { 'partner': 'store3', 'sid': 'sid_1', 'oid': 'plastic-bread', 'price': 88.4, 'fees': { 'mastercard': 1, 'visa': 1, 'paypal': 2, 'wiretransfer': 0 } }, 
        'sid_1#plastic-bread#store4': { 'partner': 'store4', 'sid': 'sid_1', 'oid': 'plastic-bread', 'price': 97.8, 'fees': { 'mastercard': 1, 'visa': 1, 'paypal': 2, 'wiretransfer': 0 } } 
        ... 
    } 
    

    由于性能原因代码将无法汇总数据,而是将分别返回它们(搜索,报价和优惠的价格)和前端将它们聚合起来,将允许我(几乎)直接从弹性流式传输数据,而不必预先详细说明它们。

    提取搜索和报价后,我想:

    • 由OID
    • 提取的价格为SID sid_1
    • 到组的价格由价格汇总排序(或按价格+特定费用,但我可以用groovy处理这个问题)
  • +1

    可否请你用一个更具体的样本延长你的问题上的数据看起来像以及您想要执行哪种查询和聚合?你想达到什么目标? –

    回答

    1

    我发现了聚合类型scripted_metric的存在,并且在玩之后我想出了这个查询

    { 
        "size": 0, 
        "query" : { 
         "match_all" : {} 
        }, 
    
        "aggs": { 
         "offer_prices": { 
          "scripted_metric": { 
           "init_script" : "_agg[\"offers_prices\"] = [:].withDefault{[:]}", 
    
           "map_script" : "def parent = doc._parent.value; def partner = doc.partner.value; def price = doc.price.value; if (!_agg.offers_prices.containsKey(parent)) { _agg.offers_prices[parent] = [ parent: parent, sid: doc.sid.value, oid: doc.oid.value, bestPrice: Double.MAX_VALUE, bestPartner: null, partners: [:] ]; }; _agg.offers_prices[parent].partners[partner] = [ \"partner\": partner, \"price\": price, \"ccfees\": _source.ccfees ]; if (_agg.offers_prices[parent].bestPrice > price) { _agg.offers_prices[parent].bestPrice = price; _agg.offers_prices[parent].bestPartner = partner; }", 
    
           "combine_script" : "return _agg.offers_prices;", 
    
           "reduce_script" : "def offers_prices_all = [:]; _aggs.each { offers_prices_per_shard -> offers_prices_per_shard.each { oid, offers_prices -> offers_prices_all[oid] = offers_prices}; }; offers_prices_all = offers_prices_all.sort { a, b -> a.value.bestPrice <=> b.value.bestPrice }; return offers_prices_all;" 
    
          } 
         } 
        } 
    } 
    

    这不是最终版本,我必须做一些修正,我要测试性能,但它似乎是一个可能的解决方案:使用_parent

    • 查询组数据计算TE最佳价格聚集的
    • 排序聚合由最佳价格

    静止TODO:

    • 排序聚集的最佳价格+费用
    • 按价格排序单聚集的合作伙伴名单
    • 测试的性能和资源消耗

    注:

    • 我已经添加了_parent映射,并且我正在使用文档的_parent属性来分组数据,但可以手动进行保佑它串联SID和OID
    • 脚本是使用属性ccfees,但在这个例子中数据集我张贴时则称为费
  • +0

    干得好,伙计! –