Tổng hợp cha-con nhiều cấp độ ElasticSearch


79

Tôi có cấu trúc cha / con ở 3 cấp độ. Hãy cùng nói nào:

Công ty -> Nhân viên -> Tính khả dụng

Vì Tính sẵn sàng (và cả Nhân viên) được cập nhật thường xuyên ở đây, tôi chọn sử dụng cấu trúc cha / con so với lồng nhau. Và chức năng tìm kiếm hoạt động tốt (tất cả các tài liệu theo đúng phân đoạn).

Bây giờ tôi muốn sắp xếp các kết quả đó. Sắp xếp chúng theo dữ liệu meta từ công ty (cấp 1) rất dễ dàng. Nhưng tôi cũng cần sắp xếp theo cấp độ thứ 3 (tính khả dụng).

Tôi muốn danh sách các công ty được sắp xếp theo:

  • Khoảng cách từ vị trí đã cho ASC
  • Xếp hạng DESC
  • Sớm nhất có sẵn ASC

Ví dụ:

Công ty A là 5 dặm, đã xếp hạng 4 và một thời gian sớm nhất của nhân viên của họ có sẵn trong 20 giờ Công ty B cũng là 5 dặm, cũng đã rating 4 nhưng một thời gian sớm nhất của nhân viên của họ có sẵn trong 5 giờ.

Do đó kết quả sắp xếp cần phải là B, A.

Tôi muốn thêm trọng số đặc biệt vào mỗi dữ liệu này, vì vậy tôi bắt đầu viết các tổng hợp mà sau này tôi có thể sử dụng trong tập lệnh custom_score của mình.

Ý chính đầy đủ để tạo chỉ mục, nhập dữ liệu và tìm kiếm

Bây giờ, tôi đã viết được một truy vấn thực sự trả về kết quả trả về, nhưng nhóm tổng hợp tính sẵn có trống. Tuy nhiên, tôi cũng nhận được kết quả quá cấu trúc, tôi muốn làm phẳng chúng.

Hiện tại tôi nhận được trở lại:

IDS công ty -> IDS nhân viên -> khả dụng đầu tiên

Tôi muốn có tổng hợp như:

IDS công ty -> tính khả dụng đầu tiên

Bằng cách này, tôi có thể thực hiện custom_scorekịch bản của mình để tính điểm và sắp xếp chúng hợp lý.

Câu hỏi đơn giản hơn:
Làm thế nào một người có thể sắp xếp / tổng hợp theo nhiều cấp độ con (lớn) và có thể làm phẳng kết quả.


Bạn có thể thêm ánh xạ của mình và một vài tài liệu mẫu (với phần con) vào ý chính không? Thật khó để biết cách phát minh tài liệu giả cho phép kiểm tra đầy đủ hệ thống của bạn.
Sloan Ahrens

Xin chào Sloan - Tôi đã thêm các kết quả mẫu và ánh xạ. Tôi đã lược bỏ nó một chút để dễ hiểu hơn. Ngăn xếp đầy đủ có nhiều dữ liệu hơn trong đó :) Cảm ơn!
Pete Minus

Tôi đã có cùng một câu hỏi ở đây . Mặc dù có thể kém hiệu quả hơn, tôi chỉ yêu cầu tất cả các kết quả có loại DocCount mặc định. Sau đó, tôi đã làm phẳng, sắp xếp và giới hạn đệ quy của riêng mình, điều này không lý tưởng.
Matt Traynham

1
Tôi đã thực thi ý chính của bạn, nhưng khi tìm kiếm, tôi gặp lỗi 500 Query Failed [Failed to execute main query]]; nested: NullPointerException;. Bạn có thể thực thi ý chính của mình trên môi trường cục bộ và đảm bảo rằng nó ổn không? Cảm ơn!
Val

Tại sao không tạo phương trình cho kết quả của bạn. Dữ liệu của bạn không mờ! Bạn tổng hợp mọi truy vấn? . Tổng hợp là các hành động đầu vào, không phải là một truy vấn hoặc đầu ra. Một câu hỏi "làm thế nào bạn kiểm tra kết quả này là True (phải)?"
dsgdfg

Câu trả lời:


3

Bạn không cần tổng hợp để làm điều này:

Đây là các tiêu chí sắp xếp:

  1. Khoảng cách ASC (company.location)
  2. Xếp hạng DESC (company.rating_value)
  3. ASC sẵn có trong tương lai sớm nhất (company.employee.available.start)

Nếu bạn bỏ qua # 3, thì bạn có thể chạy một truy vấn công ty tương đối đơn giản như sau:

GET /companies/company/_search
{
 "query": { "match_all" : {} },
 "sort": {
    "_script": {
        "params": {
            "lat": 51.5186,
            "lon": -0.1347
        },
        "lang": "groovy",
        "type": "number",
        "order": "asc",
        "script": "doc['location'].distanceInMiles(lat,lon)"
    },
    "rating_value": { "order": "desc" }
  }
}

# 3 là phức tạp vì bạn cần phải tiếp cận và tìm tình trạng sẵn có ( công ty> nhân viên> tình trạng còn hàng ) cho từng công ty gần nhất với thời điểm yêu cầu và sử dụng thời lượng đó làm tiêu chí sắp xếp thứ ba .

Chúng tôi sẽ sử dụng một function_scoretruy vấn ở cấp cháu để tính chênh lệch thời gian giữa thời gian yêu cầu và mỗi tính khả dụng trong lần truy cập _score. (Sau đó, chúng tôi sẽ sử dụng _scorelàm tiêu chí sắp xếp thứ ba).

Để tiếp cận các cháu, chúng ta cần sử dụng một has_childtruy vấn bên trong một has_childtruy vấn.

Đối với mỗi công ty, chúng tôi muốn có Nhân viên sẵn sàng sớm nhất (và tất nhiên là Sẵn sàng gần nhất của họ). Elasticsearch 2.0 sẽ cung cấp cho chúng tôi một "score_mode": "min"trường hợp như thế này, nhưng hiện tại, vì chúng tôi bị giới hạn nên "score_mode": "max"chúng tôi sẽ làm cho đứa cháu _scoretrở thành đối ứng của chênh lệch thời gian.

          "function_score": {
            "filter": { 
              "range": { 
                "start": {
                  "gt": "2014-12-22T10:34:18+01:00"
                } 
              }
            },
            "functions": [
              {
                "script_score": {
                  "lang": "groovy",
                  "params": {
                      "requested": "2014-12-22T10:34:18+01:00",
                      "millisPerHour": 3600000
                   },
                  "script": "1 / ((doc['availability.start'].value - new DateTime(requested).getMillis()) / millisPerHour)"
                }
              }
            ]
          }

Vì vậy, bây giờ _scorecho mỗi cháu ( Tính khả dụng ) sẽ là 1 / number-of-hours-until-available(để chúng tôi có thể sử dụng thời gian đối ứng tối đa cho đến khi có sẵn cho mỗi Nhân viên và số nhân viên đối ứng tối đa (ly?) Có sẵn cho mỗi Công ty).

Kết hợp tất cả lại với nhau, chúng tôi tiếp tục truy vấn công ty nhưng sử dụng công ty> nhân viên> tính khả dụng để tạo ra _scoređể sử dụng làm tiêu chí sắp xếp số 3 :

GET /companies/company/_search
{
 "query": { 
    "has_child" : {
        "type" : "employee",
        "score_mode" : "max",
        "query": {
          "has_child" : {
            "type" : "availability",
            "score_mode" : "max",
            "query": {
              "function_score": {
                "filter": { 
                  "range": { 
                    "start": {
                      "gt": "2014-12-22T10:34:18+01:00"
                    } 
                  }
                },
                "functions": [
                  {
                    "script_score": {
                      "lang": "groovy",
                      "params": {
                          "requested": "2014-12-22T10:34:18+01:00",
                          "millisPerHour": 3600000
                       },
                      "script": "1/((doc['availability.start'].value - new DateTime(requested).getMillis()) / millisPerHour)"
                    }
                  }
                ]
              }
            }
          }
        }
    }
 },
 "sort": {
  "_script": {
    "params": {
        "lat": 51.5186,
        "lon": -0.1347
    },
    "lang": "groovy",
    "type": "number",
    "order": "asc",
    "script": "doc['location'].distanceInMiles(lat,lon)"
  },
  "rating_value": { "order": "desc" },
  "_score": { "order": "asc" }
 }
}

Bạn có thể nhận được hiệu suất tốt hơn một chút bằng cách sử dụng hàm giảm dần tuyến tính chứ không phải là một tập lệnh để tạo _scoretừ thời gian cho đến khi có sẵn .
Peter Dixon-Moses

Elasticsearch đã tắt tập lệnh động theo mặc định. Tốt hơn là sử dụng các tập lệnh được lập chỉ mục. Xem tại đây : astic.co/blog/…
schellingerht

Pete Minus: Bạn có thể làm cho nó hoạt động không? Tôi biết đây là một câu hỏi cũ hơn, tuy nhiên có rất nhiều người quan tâm đến giải pháp của bạn.
Peter Dixon-Moses

Peter Dixon-Moses: Cuối cùng tôi đã từ bỏ và viết hai truy vấn - đầu tiên là tìm kiếm theo Công ty / Nhân viên và sau đó tìm kiếm 100 Công ty hàng đầu thông qua Tính khả dụng và sau đó hợp nhất. Tại sao? Mất quá nhiều thời gian / nỗ lực để xây dựng nó chỉ trong ES. Thời gian dành cho việc tìm kiếm có thể chấp nhận được.
Pete Minus

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.