2014-11-03 40 views
2

我是elasticsearch的新手,所以也许我的方法显然是错误的,但我想做一个食谱的索引并允许用户过滤它与在子集中仍然存在的聚合成分进行比较。弹性搜索中的嵌套过滤与多个相同嵌套类型的术语

也许我使用错误的语言来解释,所以也许这个例子将澄清。我想搜索术语salt的食谱;这导致了三个配方:

  1. 与配料:盐,面粉,水
  2. 与配料:盐,胡椒粉,鸡蛋
  3. 与配料:水,面粉,鸡蛋,盐

结果成分上的总量返回盐,面粉,水,胡椒,鸡蛋。当我用flour过滤时,我只想让配方1和3出现在搜索结果中(并且成分上的聚合物应该只返回盐,面粉,水,蛋和盐)。当我添加另一个过滤器egg我想只有配方3出现(和聚合物应该只返回水,面粉,鸡蛋,盐)。

我不能让后者的工作:一个过滤器旁边的默认查询缩小结果按需要而加入其他项(蛋)的条款时,过滤结果再次开始包含b,就好像它是一个OR过滤器。然而,将AND添加到筛选器执行结果中没有结果...我做错了什么?

我的映射:

{ 
    "recipe": { 
    "properties": { 
     "title": { 
     "analyzer": "dutch", 
     "type": "string" 
     }, 
     "ingredients": { 
     "type": "nested", 
     "properties": { 
      "name": { 
      "type": "string", 
      "analyzer": "dutch", 
      "include_in_parent": true, 
      "fields": { 
       "raw": { 
       "type": "string", 
       "index": "not_analyzed" 
       } 
      } 
      } 
     } 
     } 
    } 
    } 
} 

我的查询:

{ 
    "query": { 
    "filtered": { 
     "query": { 
     "bool": { 
      "should": [ 
      { 
       "match": { 
       "_all": "salt" 
       } 
      } 
      ] 
     } 
     }, 
     "filter": { 
     "nested": { 
      "path": "ingredients", 
      "filter": { 
      "terms": { 
       "ingredients.name": [ 
       "flour", 
       "egg" 
       ], 
       "execution": "and" 
      } 
      } 
     } 
     } 
    } 
    }, 
    "size": 50, 
    "aggregations": { 
    "ingredients": { 
     "nested": { 
     "path": "ingredients" 
     }, 
     "aggregations": { 
     "count": { 
      "terms": { 
      "field": "ingredients.name.raw" 
      } 
     } 
     } 
    } 
    } 
} 

回答

2

你为什么要使用这里nested映射?它的主要目的是保持子对象属性之间的关系,但是您的ingredients字段只有一个属性,并且可以简单地建模为字符串字段。

所以,如果你更新你的映射是这样的:

POST recipes 
{ 
    "mappings": { 
    "recipe": { 
     "properties": { 
     "title": { 
      "type": "string" 
     }, 
     "ingredients": { 
      "name": { 
      "type": "string", 
      "fields": { 
       "raw": { 
       "type": "string", 
       "index": "not_analyzed" 
       } 
      } 
      } 
     } 
     } 
    } 
    } 
} 

你仍然可以索引你的食谱:

{ 
    "title":"recipe b", 
    "ingredients":["salt","pepper","egg"] 
} 

而且此查询为您提供了正在等待结果:

POST recipes/recipe/_search 
{ 
    "query": { 
    "filtered": { 
     "query": { 
     "match": { 
      "_all": "salt" 
     } 
     }, 
     "filter": { 
     "terms": { 
      "ingredients": [ 
      "flour", 
      "egg" 
      ], 
      "execution": "and" 
     } 
     } 
    } 
    }, 
    "size": 50, 
    "aggregations": { 
    "ingredients": { 
     "terms": { 
     "field": "ingredients" 
     } 
    } 
    } 
} 

这是:

{ 
    ... 
    "hits": { 
     "total": 1, 
     "max_score": 0.22295055, 
     "hits": [ 
     { 
      "_index": "recipes", 
      "_type": "recipe", 
      "_id": "PP195TTsSOy-5OweArNsvA", 
      "_score": 0.22295055, 
      "_source": { 
       "title": "recipe c", 
       "ingredients": [ 
        "salt", 
        "flour", 
        "egg", 
        "water" 
       ] 
      } 
     } 
     ] 
    }, 
    "aggregations": { 
     "ingredients": { 
     "buckets": [ 
      { 
       "key": "egg", 
       "doc_count": 1 
      }, 
      { 
       "key": "flour", 
       "doc_count": 1 
      }, 
      { 
       "key": "salt", 
       "doc_count": 1 
      }, 
      { 
       "key": "water", 
       "doc_count": 1 
      } 
     ] 
     } 
    } 
} 

希望这会有所帮助。

+0

我正朝着这个方向发展,但您给出了完整的答案(实际上我在嵌套对象旁边添加了一个字符串数组,但是正如您所建议的那样,此时是一种过度工程)。谢谢!重复的事情很多:) – murb 2014-11-04 12:42:56

+0

谢谢是不够的:非常感谢你这个广泛的答案! – murb 2014-11-04 12:50:26

+0

不客气:)您使用嵌套对象的问题是您的“条款”过滤条件过滤了“成分”子对象,该对象在同一子对象中将具有“蛋”和“面粉”。 – ThomasC 2014-11-04 12:51:38