2014-01-23 4 views
4

우리의 데이터는 MongoDB 2.4.8에 저장되고 ElasticSearch MongoDB River 1.7.3을 사용하여 ElasticSearch 0.90.7로 인덱싱됩니다.ElasticSearch : 깊게 중첩 된 데이터에 대한 필터링

데이터 색인이 올바르게 색인되어 있으며 검색하려는 필드를 성공적으로 검색 할 수 있습니다. 그러나 나는 또한 허가를 받아 들일 필요가있다. 물론 호출 사용자가 실제로 읽을 수있는 결과 만 반환하기를 원할 뿐이다. 우리 서버의 코드에서

, 내가 예를 들어, 배열로 호출하는 사용자의 권한을 가지고

[ "Role:REGISTERED_USER", "Account:52c74b25da06f102c90d52f4", "Role:USER", "Group:52cb057cda06ca463e78f0d7" ] 

우리가 검색하는 단위 데이터의 예는 다음과 같습니다

{ 
    "_id" : ObjectId("52dffbd6da06422559386f7d"), 
    "content" : "various stuff", 
    "ownerId" : ObjectId("52d96bfada0695fcbdb41daf"), 
    "acls" : [ 
     { 
      "accessMap" : {}, 
      "sourceClass" : "com.bulb.learn.domain.units.PublishedPageUnit", 
      "sourceId" : ObjectId("52dffbd6da06422559386f7d") 
     }, 
     { 
      "accessMap" : { 
       "Role:USER" : { 
        "allow" : [ 
         "READ" 
        ] 
       }, 
       "Account:52d96bfada0695fcbdb41daf" : { 
        "allow" : [ 
         "CREATE", 
         "READ", 
         "UPDATE", 
         "DELETE", 
         "GRANT" 
        ] 
       } 
      }, 
      "sourceClass" : "com.bulb.learn.domain.units.CompositeUnit", 
      "sourceId" : ObjectId("52dffb54da06422559386f57") 
     } 
    ] 
} 

위의 샘플 데이터에서 검색 가능한 모든 콘텐츠를 "content" : "various stuff"

으로 바 꾸었습니다. 인증 데이터는 "acls"ar 레이. 나는 (영어로) 다음을 수행 할 작성할 필요가 필터 : 권한 부여 및 본 기기가있는 accessMap 있습니다 위의 예에서

pass all units where the "acls" array 
contains an "accessMap" object 
that contains a property whose name is one of the user's authorization strings 
and whose "allow" property contains "READ" 
and whose "deny" property does not contain "READ" 

, 사용자는 "사용자 역할"을 가지고 "역할 : 사용자를" , "READ"및 "Role : USER"가 포함 된 "allow"가 들어있는 파일에는 "deny"가 없습니다. 그래서이 유닛은 필터를 통과 할 것입니다.

ElasticSearch를 사용하여 필터를 작성하는 방법이 표시되지 않습니다.

"중첩 된"또는 "has_child"(또는 "has_parent")와 같이 중첩 된 배열을 처리하는 두 가지 방법이 있다는 인상을받습니다.

"중첩 된"필터는 데이터가 변경 될 때 전체 블록을 다시 인덱싱해야하기 때문에 꺼려합니다. 검색 가능한 컨텐츠 및 권한 부여 데이터는 사용자 조치에 따라 언제든지 변경 될 수 있습니다.

"has_child"또는 "has_parent"를 사용하려면 권한 부여 데이터가 다른 컬렉션의 유닛 데이터와 분리되어 있어야하며 노드가 인덱싱되면 부모 또는 자녀를 지정해야합니다. 나는 ElasticSearch MongoDB River가 이것을 할 수 있는지 여부를 모른다.

이렇게해도 될까요? 또는 승인 데이터를 재 배열해야합니까?

+0

서로 다른 액세스 수준에 대해 별도의 색인을 사용하고 ES 상단의 프록시에 대한 액세스 제어를 강화할 것입니다. – opyate

답변

-5

감사합니다, @ 알렉스 Brasetvik, 당신의 제안 대신 키의 대상 ID가 데이터를 만들기 위해, 그리고 중첩 된 "update-per-update"가 부모 - 자식이 "join-per-query"인 설명이 가장 도움이되었습니다.

나는 부모 - 자식 접근법을 사용하기 위해 데이터를 "un-nest"해야한다는 것을 알았고 인증 데이터를 중첩 된 상태로 유지하는 것을 선호합니다.

당신이 의미하는 바를 이해하지 못합니다. "그 안에 bool이 두 개 들어있는 것은 효과가 없습니다."

{ 
    "_id" : ObjectId("52dffbd6da06422559386f7d"), 
    "content" : "various stuff", 
    "ownerId" : ObjectId("52d96bfada0695fcbdb41daf"), 
    "accessMaps" : [ 
     { 
      "sourceClass" : "com.bulb.learn.domain.units.PublishedPageUnit", 
      "sourceId" : ObjectId("52dffbd6da06422559386f7d") 
     }, 
     { 
      "allow" : { 
       "CREATE" : [ 
        "Account:52d96bfada0695fcbdb41daf" 
       ], 
       "READ" : [ 
        "Account:52d96bfada0695fcbdb41daf", 
        "Role:USER" 
       ], 
       "UPDATE" : [ 
        "Account:52d96bfada0695fcbdb41daf" 
       ], 
       "DELETE" : [ 
        "Account:52d96bfada0695fcbdb41daf" 
       ], 
       "GRANT" : [ 
        "Account:52d96bfada0695fcbdb41daf" 
       ] 
      }, 
      "deny" : {}, 
      "sourceClass" : "com.bulb.learn.domain.units.CompositeUnit", 
      "sourceId" : ObjectId("52dffb54da06422559386f57") 
     } 
    ] 
} 

새로운 매핑은 다음과 같습니다 :

{ 
    "unit": { 
    "properties": { 
     "accessMaps": { 
     "type": "nested", 
     "properties": { 
      "allow": { 
      "type": "nested", 
      "properties": { 
       "CREATE": { 
       "type": "string", 
       "index": "not_analyzed", 
       }, 
       "DELETE": { 
       "type": "string", 
       "index": "not_analyzed", 
       }, 
       "GRANT": { 
       "type": "string", 
       "index": "not_analyzed", 
       }, 
       "READ": { 
       "type": "string", 
       "index": "not_analyzed", 
       }, 
       "UPDATE": { 
       "type": "string", 
       "index": "not_analyzed", 
       } 
      } 
      },  
      "deny": { 
      "type": "nested", 
      "properties": { 
       "CREATE": { 
       "type": "string", 
       "index": "not_analyzed", 
       }, 
       "DELETE": { 
       "type": "string", 
       "index": "not_analyzed", 
       }, 
       "GRANT": { 
       "type": "string", 
       "index": "not_analyzed", 
       }, 
       "READ": { 
       "type": "string", 
       "index": "not_analyzed", 
       }, 
       "UPDATE": { 
       "type": "string", 
       "index": "not_analyzed", 
       } 
      } 
      },  
      "sourceClass": { 
      "type": "string" 
      }, 
      "sourceId": { 
      "type": "string" 
      } 
     } 
     } 
    } 
    } 
} 

을 그리고 필터링 된 쿼리는 다음과 같습니다

{ 
    "query": { 
    "filtered": { 
     "query": { 
     "match_all": {} 
     }, 
     "filter": { 
     "bool": { 
      "must": { 
      "nested": { 
       "path": "accessMaps.allow", 
       "filter": { 
       "terms": { 
        "accessMaps.allow.READ": [ 
        "Role:REGISTERED_USER", 
        "Account:52e6a361da06e4eb64172519", 
        "Role:USER", 
        "Group:52cb057cda06ca463e78f0d7" 
        ] 
       } 
       } 
      } 
      }, 
      "must_not": { 
      "nested": { 
       "path": "accessMaps.deny", 
       "filter": { 
       "terms": { 
        "accessMaps.deny.READ": [ 
        "Role:REGISTERED_USER", 
        "Account:52e6a361da06e4eb64172519", 
        "Role:USER", 
        "Group:52cb057cda06ca463e78f0d7" 
        ] 
       } 
       } 
      } 
      } 
     } 
     } 
    } 
    } 
} 

가장 큰 문제는 여기에

내가 데이터를 리팩토링 방법 나는 중첩 된 필터에서 "경로"속성을 사용하는 방법을 알아 냈고 그 필드 이름은 erms 필터는 완전해야합니다. ElasticSearch가 그들의 문서에 더 많은 노력을 기울 이길 바란다.

+4

당신은 진지하게 다른 사람의 대답을 받아 들여 자신의 것으로 풀어 냈습니다. WTF? – hackel

9

데이터를 약간 재구성해야합니다.

키에 값이 있으면 Elasticsearch에 문제가 있습니다. 그것은 별도의 필드로 끝날 것이고, 당신은 계속 증가하는 매핑을 가지게 될 것이며 결과적으로 클러스터 상태가 될 것입니다.

아마도 현재 값의 키가있는 객체 목록 인 accessMap을 원하게됩니다. 그런 다음 중첩되어야합니다. 그렇지 않으면 일치하는 허용이 속한 accessMap을 알 수 없습니다.

ACL을 중첩해야 (두 가지 중첩 수준이 발생 함) 또는 상위 - 자식이 다양한 개체를 업데이트하는 빈도에 따라 달라집니다. 객체에 중첩 된 문서로 설정하면 업데이트 될 때마다 가입 비용이 발생합니다. 부모 - 자식을 수행하는 경우 모든 검색에서 가입 비용을 지불해야합니다.

이 빠르게 복잡해진다, 그래서 당신이 재생할 수있는 단순화 된 실행 가능한 예를 준비한 다음 nested 방법 https://www.found.no/play/gist/8582654

주 - 및 bool -filters는, 음, 중첩됩니다. 그 안에 bool이 둘 중첩되어있는 것은 효과가 없습니다. 완성도를 들어

#!/bin/bash 

export ELASTICSEARCH_ENDPOINT="http://localhost:9200" 

# Create indexes 

curl -XPUT "$ELASTICSEARCH_ENDPOINT/play" -d '{ 
    "settings": { 
     "analysis": {} 
    }, 
    "mappings": { 
     "type": { 
      "properties": { 
       "acls": { 
        "type": "nested", 
        "properties": { 
         "accessMap": { 
          "type": "nested", 
          "properties": { 
           "allow": { 
            "type": "string", 
            "index": "not_analyzed" 
           }, 
           "deny": { 
            "type": "string", 
            "index": "not_analyzed" 
           }, 
           "key": { 
            "type": "string", 
            "index": "not_analyzed" 
           } 
          } 
         } 
        } 
       } 
      } 
     } 
    } 
}' 


# Index documents 
curl -XPOST "$ELASTICSEARCH_ENDPOINT/_bulk?refresh=true" -d ' 
{"index":{"_index":"play","_type":"type","_id":1}} 
{"acls":[{"accessMap":[{"key":"Role:USER","allow":["READ"]},{"key":"Account:52d96bfada0695fcbdb41daf","allow":["READ","UPDATE"]}]}]} 
{"index":{"_index":"play","_type":"type","_id":2}} 
{"acls":[{"accessMap":[{"key":"Role:USER","allow":["READ"]},{"key":"Account:52d96bfada0695fcbdb41daf","deny":["READ","UPDATE"]}]}]} 
{"index":{"_index":"play","_type":"type","_id":3}} 
{"acls":[{"accessMap":[{"key":"Role:USER","allow":["READ"]},{"key":"Account:52d96bfada0695fcbdb41daf","allow":["READ","UPDATE"]}]}]} 
' 

# Do searches 

curl -XPOST "$ELASTICSEARCH_ENDPOINT/_search?pretty" -d ' 
{ 
    "query": { 
     "filtered": { 
      "filter": { 
       "nested": { 
        "path": "acls", 
        "filter": { 
         "bool": { 
          "must": { 
           "nested": { 
            "path": "acls.accessMap", 
            "filter": { 
             "bool": { 
              "must": [ 
               { 
                "term": { 
                 "allow": "READ" 
                } 
               }, 
               { 
                "terms": { 
                 "key": [ 
                  "Role:USER", 
                  "Account:52d96bfada0695fcbdb41daf" 
                 ] 
                } 
               } 
              ] 
             } 
            } 
           } 
          }, 
          "must_not": { 
           "nested": { 
            "path": "acls.accessMap", 
            "filter": { 
             "bool": { 
              "must": [ 
               { 
                "term": { 
                 "deny": "READ" 
                } 
               }, 
               { 
                "terms": { 
                 "key": [ 
                  "Role:USER", 
                  "Account:52d96bfada0695fcbdb41daf" 
                 ] 
                } 
               } 
              ] 
             } 
            } 
           } 
          } 
         } 
        } 
       } 
      } 
     } 
    } 
} 
' 

, 여기에 부모 - 자식-접근 방식에 대해 유사한 예입니다 https://www.found.no/play/gist/8586840

#!/bin/bash 

export ELASTICSEARCH_ENDPOINT="http://localhost:9200" 

# Create indexes 

curl -XPUT "$ELASTICSEARCH_ENDPOINT/play" -d '{ 
    "settings": { 
     "analysis": {} 
    }, 
    "mappings": { 
     "acl": { 
      "_parent": { 
       "type": "document" 
      }, 
      "properties": { 
       "acls": { 
        "properties": { 
         "accessMap": { 
          "type": "nested", 
          "properties": { 
           "key": { 
            "type": "string", 
            "index": "not_analyzed" 
           }, 
           "allow": { 
            "type": "string", 
            "index": "not_analyzed" 
           }, 
           "deny": { 
            "type": "string", 
            "index": "not_analyzed" 
           } 
          } 
         } 
        } 
       } 
      } 
     } 
    } 
}' 


# Index documents 
curl -XPOST "$ELASTICSEARCH_ENDPOINT/_bulk?refresh=true" -d ' 
{"index":{"_index":"play","_type":"document","_id":1}} 
{"title":"Doc 1"} 
{"index":{"_index":"play","_type":"acl","_parent":1}} 
{"acls":[{"accessMap":[{"key":"Role:USER","allow":["READ"]},{"key":"Account:52d96bfada0695fcbdb41daf","allow":["READ","UPDATE"]}]}]} 
{"index":{"_index":"play","_type":"document","_id":2}} 
{"title":"Doc 2"} 
{"index":{"_index":"play","_type":"acl","_parent":2}} 
{"acls":[{"accessMap":[{"key":"Role:USER","allow":["READ"]},{"key":"Account:52d96bfada0695fcbdb41daf","deny":["READ","UPDATE"]}]}]} 
' 

# Do searches 

curl -XPOST "$ELASTICSEARCH_ENDPOINT/_search?pretty" -d ' 
{ 
    "query": { 
     "filtered": { 
      "filter": { 
       "has_child": { 
        "type": "acl", 
        "filter": { 
         "bool": { 
          "must": [ 
           { 
            "nested": { 
             "path": "acls.accessMap", 
             "filter": { 
              "bool": { 
               "must": [ 
                { 
                 "terms": { 
                  "key": [ 
                   "Role:USER", 
                   "Account:52d96bfada0695fcbdb41daf" 
                  ] 
                 } 
                }, 
                { 
                 "term": { 
                  "allow": "READ" 
                 } 
                } 
               ] 
              } 
             } 
            } 
           } 
          ], 
          "must_not": [ 
           { 
            "nested": { 
             "path": "acls.accessMap", 
             "filter": { 
              "bool": { 
               "must": [ 
                { 
                 "terms": { 
                  "key": [ 
                   "Role:USER", 
                   "Account:52d96bfada0695fcbdb41daf" 
                  ] 
                 } 
                }, 
                { 
                 "term": { 
                  "deny": "READ" 
                 } 
                } 
               ] 
              } 
             } 
            } 
           } 
          ] 
         } 
        } 
       } 
      } 
     } 
    } 
} 
' 
+0

답을 업데이트하여 부모 - 자식 매핑이있는 비슷한 예도 포함 시켰습니다. –

+0

감사합니다. 나는 당신의 모범을 연구하고 다시 생각해 보겠습니다. –

+0

하나의 중요한 단순화가 가능합니다. 왜냐하면 어떤 accessMap 허용 또는 거부가 발생하는지 실제로는 신경 쓰지 않기 때문입니다. 일치하는 거부가 있으면 필터가 실패해야하고 그렇지 않으면 일치하는 허용이 있으면 필터가 성공해야합니다. 이렇게하면 중첩을 완전히 제거 할 수 있습니까? –

관련 문제