背景, 需求

有业务部门要用elasticsearch做酒店搜索, 大概的数据类型如下.

#parent
POST indexname/hotel/_mapping
{
   "properties": {
      "hotelid": {
         "type": "long"
      },
      "name": {
         "type": "string"
      }
   }
}

#child
POST indexname/room/_mapping
{
   "_parent": {
      "type": "hotel"
   },
   "properties": {
      "roomid": {
         "type": "long"
      },
      "price": {
         "type": "long"
      },
      "area": {
         "type": "float"
      }
   }
}

父类型是酒店, 下面有子类型, 是房间, 每个房间的面积和价格不一样.

搜索的时候, 结果是展示酒店, 但以每个房间的最小价格排序.

有一方案是把room做为一个字段(列表)放到hotel里面去, 但这样的话, 每更新一个房间信息, 其实都是更新了整个hotel文档. 所以还是希望做成parent/children结构.

用has_child搜索方式, 再结合自定义打分功能, 可以实现.

准备一下数据

插入几条酒店信息

POST indexname/hotel/1
{
   "hotelid": 1,
   "name": "abc"
}
POST indexname/hotel/2
{
   "hotelid": 2,
   "name": "xyz"
}

再插入几条房间信息

POST indexname/room/a?parent=1
{
   "price": 100
}
POST indexname/room/b?parent=2
{
   "price": 200
}
POST indexname/room/c?parent=3
{
   "price": 300
}

搜索

POST indexname/hotel/_search
{
   "query": {
      "has_child": {
         "type": "room",
         "score_mode": "max",
         "query": {
            "function_score": {
               "query": {},
               "script_score": {
                  "script": "-1*doc['price'].value"
               }
            }
         }
      }
   }
}

搜索结果

{
   "took": 9,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 2,
      "max_score": -100,
      "hits": [
         {
            "_index": "indexname",
            "_type": "hotel",
            "_id": "1",
            "_score": -100,
            "_source": {
               "hotelid": 1,
               "name": "abc"
            }
         },
         {
            "_index": "indexname",
            "_type": "hotel",
            "_id": "2",
            "_score": -200,
            "_source": {
               "hotelid": 2,
               "name": "xyz"
            }
         }
      ]
   }
}