2014-11-05 2 views
2

흥미로운 점은 인덱스 버킷과 스토리지 해시를 관리하는 버킷 샤딩 시스템에 시나리오가 있다는 것입니다. 상호 연관성은 생성 된 UUID이며 분산되어 있기 때문에 새 버킷에 고유 참조가 필요하다는 확신이 필요합니다. .Ruby에서 해시의 키에 사용되는 특정 객체를 얻는 편리한 방법은 무엇입니까?

이 연습의 초기에 나는 해시에서 문자열을 키로 사용하면 속도록 채워지고 자동으로 동결되어 코드가 생성 될 수 있음을 보장하기 때문에 SecureRandom.uuid (문자열 생성)로 생성 된 모든 키를 고정 시키도록 코드를 최적화하기 시작했습니다. 변경되지 않습니다. (문자열이고 얼지 않는 경우).

대부분의 경우 적극적으로 이것을 수행하는 것이 쉽습니다. 특히 새로운 UUID의 경우 (실제로이 프로젝트에 많은 가치가 필요합니다.)하지만 어떤 경우에는이 값을 넘는 값으로 해시에 접근해야하는 경우가 있습니다. 네트워크를 구축하고 획득하면 키로 나타나는 문자열을 일관되게 사용하기 위해 오히려 둔한 조회 메커니즘을 사용하십시오.

내 목표는 여러 노드에서 거대한 데이터 세트를 유지하면서 가능한 한 키 및 색인 저장소의 오버 헤드를 줄이고 버킷 시스템이기 때문에 같은 UUID를 여러 번 참조 할 수 있기 때문입니다. 같은 참조를 사용하는 것이 도움이됩니다.

다음은 간단한 (ish) 형식의 문제를 보여주는 코드입니다. 나는 문자열 값이 같은 (키 이름과 관련된 값이 아닌) 키에 대한 기존의 객체 참조를 얻기위한보다 최적의 편리한 메커니즘이 있는지 묻는 것이다.

require 'securerandom' 

index = Hash.new 
store = Hash.new 
key = 'meh' 
value = 1 
uuid = SecureRandom.uuid 
store[uuid] = value 
index[key] = uuid 

# obtained from elsewhere 
uuid = uuid.dup.freeze 

uuid = store.find{|k,_| k == uuid }.first 
store[uuid] = value 
index[key] = uuid 
store.each_key { |x| puts "Store reference for value of #{x} #{x.object_id}"} 
index.each_value { |x| puts "Index reference for #{x} #{x.object_id}" } 

출력 :

012,351
Ruby dups and freezes strings if used for keys in hashes 
This produces different IDs 
Store reference for value of bd48a581-95e9-452e-b8a3-602d92d47011 70209306325780 
Index reference for bd48a581-95e9-452e-b8a3-602d92d47011 70209306325880 

If inconsistencies in ID occur then Ruby attempts to preserve the use of the frozen key so if it happens in one area take care 
This produces different IDs 
Store reference for value of bd48a581-95e9-452e-b8a3-602d92d47011 70209306325780 
Index reference for bd48a581-95e9-452e-b8a3-602d92d47011 70209306325880 

If you start with a clean slate and a frozen key you can overcome it if you freeze the string before use 
This is clean so far and produces the same object 
Store reference for value of bd48a581-95e9-452e-b8a3-602d92d47011 70209306325880 
Index reference for bd48a581-95e9-452e-b8a3-602d92d47011 70209306325880 

But if the same value for the key comes in (possibly remote) then it becomes awkward 
This produces different IDs 
Store reference for value of bd48a581-95e9-452e-b8a3-602d92d47011 70209306325880 
Index reference for bd48a581-95e9-452e-b8a3-602d92d47011 70209306325000 

So you get into oddities like this to ensure you standarise values put in to keys that already exist 
This cleans up and produces same IDs but is a little awkward 
Store reference for value of bd48a581-95e9-452e-b8a3-602d92d47011 70209306325880 
Index reference for bd48a581-95e9-452e-b8a3-602d92d47011 70209306325880 
+0

* * 참고로 잘못된 –

+0

' Hash.new'는 그 자체로 거의 사용되지 않습니다. 대신'{}'을 사용하십시오. – tadman

+0

물론 명시 적으로 장황하고 사실상 파서 성능 측면에서 제외하면 의미가 거의 없습니다. 코멘트는 구약입니다. –

답변

0

은 어쩌면 당신은 Enumerable#find

uuid = store.find{|k,_| k == uuid_from_network }.first 

전체 예를 찾고있는 예제를 실행

# Demonstrate the issue.. 

require 'securerandom' 

index = Hash.new 
store = Hash.new 

key = 'meh' 
value = 1 

uuid = SecureRandom.uuid 

puts "Ruby dups and freezes strings if used for keys in hashes" 
puts "This produces different IDs" 
store[uuid] = value 
index[key] = uuid 
store.each_key { |x| puts "Store reference for value of #{x} #{x.object_id}"} 
index.each_value { |x| puts "Index reference for #{x} #{x.object_id}" } 
puts 

puts "If inconsistencies in ID occur then Ruby attempts to preserve the use of the frozen key so if it happens in one area take care" 
puts "This produces different IDs" 
uuid = uuid.freeze 
store[uuid] = value 
index[key] = uuid 
store.each_key { |x| puts "Store reference for value of #{x} #{x.object_id}"} 
index.each_value { |x| puts "Index reference for #{x} #{x.object_id}" } 
puts 

puts "If you start with a clean slate and a frozen key you can overcome it if you freeze the string before use" 
puts "This is clean so far and produces the same object" 
index = Hash.new 
store = Hash.new 

store[uuid] = value 
index[key] = uuid 
store.each_key { |x| puts "Store reference for value of #{x} #{x.object_id}"} 
index.each_value { |x| puts "Index reference for #{x} #{x.object_id}" } 
puts 

puts "But if the same value for the key comes in (possibly remote) then it becomes awkward" 
puts "This produces different IDs" 
uuid = uuid.dup.freeze 
store[uuid] = value 
index[key] = uuid 
store.each_key { |x| puts "Store reference for value of #{x} #{x.object_id}"} 
index.each_value { |x| puts "Index reference for #{x} #{x.object_id}" } 
puts 

puts "So you get into oddities like this to ensure you standarise values put in to keys that already exist" 
puts "This cleans up and produces same IDs but is a little awkward" 

uuid = uuid.dup.freeze 
uuid_list = store.keys 
uuid = uuid_list[uuid_list.index(uuid)] if uuid_list.include?(uuid) 
store[uuid] = value 
index[key] = uuid 
store.each_key { |x| puts "Store reference for value of #{x} #{x.object_id}"} 
index.each_value { |x| puts "Index reference for #{x} #{x.object_id}" } 
puts 

...

Store reference for value of d94390c4-7cc7-4e94-92bc-a0dd862ac6a2 70190385847520 
Index reference for d94390c4-7cc7-4e94-92bc-a0dd862ac6a2 70190385847520 

효율적으로 가고 싶다면 C 함수 st_get_key 주위에 경량 래퍼를 만들면 원하는 작업을 정확하게 수행 할 수 있습니다. 나는 the implementation of Hash#has_key?을 상용구로 사용했다. C 코드를 Ruby 코드 (예 : RubyInline)로 혼합 할 수 있습니다.

require 'inline' 

class Hash 
    inline do |builder| 
    builder.c <<-EOS 
     VALUE fetch_key(VALUE key) { 
     st_data_t result; 
     if (!RHASH(self)->ntbl) 
      return Qnil; 
     if (st_get_key(RHASH(self)->ntbl, key, &result)) { 
      return result; 
     } 
     return Qnil; 
     } 
    EOS 
    end 
end 
+0

부모 Enumerable을 사용하는 우아함을 좋아하기 때문에 루비 구현에서 바로 이것을 얻을 수있는 메커니즘이 있기를 바랬습니다. Hash 직접 쿼리를하는 것이 더 깨끗합니다 (예 : has_key? 이것은 기본적으로 네이티브 코드로 구현되었으므로 참/거짓이 아닌 참조를 반환했습니다. has_key를 재정의 할 수 있습니까? 원하는 동작을 얻기 위해이 방법이나 원래의 방법을 사용하여 선호하는 동작에 대해 또는 덜 논란이되는 무언가를 추가할까요? 메소드는 true 또는 false 이외의 것을 리턴하지만 네이티브 구현 외부에서 어떤 방법 으로든 빠져 나옵니다. –

+0

그리고 미안하지만 아직 충분히 투표를 할 수 없기 때문에 미안합니다 : p –

+0

@AndrewSmith 오늘 나는 여러 가지 이유로 해쉬 구현에 대해 잠깐 보았고'st_get_key'라는 메쏘드가 있음을 알았습니다. 내 대답을 사용하는 방법의 예를 편집했습니다. 건배 –

0

순수한 Ruby 예제의 경우 심볼 객체 참조의 전체적인 특성 때문에 완전히 피할 수 있습니다. 동일한 참조를 위해 문자열을 기호로 변환하면 충분합니다. Ruby를 사용하여 C 개발자를위한 프로토 타입을 작성하기 때문에 기대했던 바가 아니지만 안정적으로 작동하며 C 개발 단계에서 많은 추가 의견으로 프로토 타입 진행을 돕는 데 적합합니다.

다른 예제에도 관심이 있지만 여기 Symbols의 큰 장점이 있습니다. 많은 네트워크의 경우 JSON을 통해 String으로 마샬링되기 때문에 피할 수 있습니다. (다른 언어로 작성된 피어는 일반적으로 지원할 수 있기 때문에 JSON을 좋아합니다. 그것).여기 또한이 방법 Why use symbols as hash keys in Ruby?

imac:Ruby andrews$ irb 
irb(main):001:0> a = :meh 
=> :meh 
irb(main):002:0> b = 'meh'.to_sym 
=> :meh 
irb(main):003:0> a.object_id == b.object_id 
=> true 

추가 백업, 심볼, 한 번, 이름이 쓰레기 수집되지 것을 기억해야합니다.

내가 해시 소스의 기본 아무것도 찾을 수 없습니다 내가 @의 p11y에서 답을 적응 있도록 기호 내 목적에 적합했다
+0

사실 더 자세히 살펴보면 유한 키 수에 대한 좋은 접근 방법이긴하지만 실제로 많은 시나리오에서 최악의 시나리오입니다. 많은 UUID 전체 양동이가 나타나고 사라짐에 따라 키가오고 갈 수 있습니다. 문자열을 키로 사용하면 역 참조 된 후에 문자열을 사용할 수 있습니다. 이 시나리오의 기호는 단지 내 힙을 날려 버릴뿐입니다. –

0

, 감사합니다 ^^

class Hash 

    def consistent_key_obj(key) 
    self.keys.include?(key) ? self.find{|k,_| k == key }.first : key 
    end 

end 
제거
관련 문제