지도에 다중마커 표시

DB의 주소를 배열로 받아와 지도에 마커를 표시해주는데요.
800여개를 뿌리면 340개정도만 표시됩니다.
혹시 마커개수 제한이 있는건가요 아니면 코드에 문제가 있는건가요?

var geocoder = new daum.maps.services.Geocoder();

for (var i = 0; i < addr.length; i++) {
        (function(i) {                                                   
        geocoder.addr2coord(addr[i], function (status, result) {
       // 정상적으로 검색이 완료됐으면 
            if (status === daum.maps.services.Status.OK) {

                var coords = new daum.maps.LatLng(result.addr[0].lat, result.addr[0].lng);

                // 지도의 중심을 결과값으로 받은 위치로 이동시킵니다
                map.setCenter(coords);

                // 결과값으로 받은 위치를 마커로 표시합니다
                var marker = new daum.maps.Marker({
                    map: map,
                    position: coords
    			 });
            }
        });
 })(i);
}

동시에 여러개의 요청을 하신 경우군요.
이거 예전에 이슈가 되어서 한 번 개선을 한 부분이긴 한데…
다시 테스트 해 보겠습니다.

감사합니다. 테스트 완료되시면 답변 꼭 부탁드립니다.

저는 나름대로 기능과 관련된 테스트를 해보겠습니다.
@shi0282 님께서는 status가 daum.maps.services.Status.OK 가 아닌 경우가 나오는지 한 번 확인해주세요.
검색 주소 쿼리에 따라 결과가 나오지 않는 경우도 있을 수 있으니까요

status는 ok로 나옵니다.

흠… 이상한데요… 사용하신 API 이름을 보아하니 변경 전 API 인데…

저도 주소 100개를 샘플링해서 동시에 여러개를 호출해봤는데
전혀 문제 없이 100개 모두 좌표를 받아왔습니다.
현제 서비스 중인 API는 제가 이전에 개선을 했다는 부분이 적용이 된 버전입니다.
Ajax 호출에서 문제가 있는건 아닌것 같습니다.

위에 첨부해주신 코드가 문제가 있어보이지도 않고요.

콜백에서 내부 마커 생성 콜백이 반복분을 실행한 만큼(800번 이상) 호출하는지 확인해주시고
죄송하지만, 데이터에 중복이 있거나 유사한 장소에 찍히는 마커가 있는지 다시 한 번 확인 부탁드립니다.

콜백에서 반복문을 실행한만큼 호출합니다.
유사한 장소 (ex 충청남도 천안시 동남구 용곡동 93-18 , 충청남도 천안시 동남구 용곡동 104-1) 가 있으면 안되는 건가요?

제가 테스트 했을때도 100개는 모두 좌표를 받아왔습니다.
죄송하지만, 400개 이상을 테스트 해주시면 감사하겠습니다.

  • 데이터에 중복이 있으면 안되는건가요?

음… 중복은 상관 없는데 혹시 같은 자리에 찍혀있을까 해서 여쭤본거고요.

많은 요청이 있는 경우에 해당 현상을 확인했습니다.
브라우저 성능에 영향을 받네요.

이런 다량의 동시 호출 상황을 상정하지 않고 만든 API이기에
내부적으로 Timeout을 5초로 두고 있었는데
이 5초가 지나고 나면 콜백 객체가 삭제가 됩니다.

지금 현상은 많은 요청에 의해 실행되는 콜백 스크립트 실행 시간에 밀려
응답 대기 시간이 5초가 넘어가는 상황이고
때문에 에러가 나고 있는 것입니다.

보통 Timeout 시간 5초 정도면 1개의 요청에 응답 받는 시간으로는 너무나도 충분합니다.
때문에 많은 사용자들이 사용하고는 있지만 큰 문제가 되지 않았는데요.
이 시간을 10초까지 늘리는 것을 고려해 보겠습니다.
다만 결국 브라우저 성능에 종속된 결과이므로
정량적인 호출을 보장할 수 없는건 마찬가지입니다. 브라우저에서 10초가 넘어가도록 연산이 밀리게 되면 똑같은 현상이 발생할거에요.
그래서 이런 사용을 하실거라면 데이터를 특정 단위로 몇 개씩 끊어서 시간을 두고 호출하는 방식으로 회피를 해야 할 듯 하네요.

원인을 알려주셔서 정말 감사합니다!

1개의 좋아요

@shi0282
10초로 늘려서 배포되었습니다.
제 크롬 브라우저에서는 800개까지 가능한 것 같은데
그 이상은 결국 똑같은 문제가 발생하긴 합니다.

^^; 양해 부탁드립니다.

약 770개까지는 지도에 표시되는것을 확인하였습니다.
정말 감사합니다!!

혹시 데이터를 특정 단위로 몇 개씩 끊어서 시간을 두고 호출하는 방식의 예제나 방법을 알 수 있을까요?

에… 500 개 정도로 끊는다고 하면
상위 스코프에 변수를 두고
콜백 함수에서 +1 씩 카운팅을 하시고
콜백 함수 내부에서 카운터가 500이 되는 순간 다음 500개를 또 콜하는 조건문을 두어
다음 500개를 추가로 요청하는 식으로 변경하시면 안전할 겁니다.

1개의 좋아요

시도를 해봤지만 어렵네요…
죄송하지만… 코드로 도움을 주실 순 없을까요…?

비록 timeout을 늘려드렸지만
이것은 단순히 @shi0282 님의 요청때문에 변경한 것이 아니라
혹시나 서버 장애로 응답이 늦어질 경우를 고려했을때 합리적인 변경이라 판단하여 그 근거로 변경한 것입니다.
때문에 질문 주신 사용 방법에 대해서는 여전히 부정적인 입장입니다.
가급적 이렇게 사용하지 않았으면 하는데요.

이게 한 사람만 사용하면 모르겠지만 실서비스로 나가서 여러 사람이 사용하게 되면
분당 리퀘스트 초과로 API 자체가 호출이 제한될 가능성도 배제할 수 없습니다.

이건 기술적인 제약을 말씀드린 것입니다.
이 리스크를 감수하고서라도 꼭 질문하신대로 구현해야만 하는 스펙인건가요?
만약 그렇다면 참고할만한 코드를 전달해 드릴 수는 있습니다만
재고해 주시길 바랍니다.

P.S.
도움을 드리기 싫어서가 아닙니다. 드리고 싶어서 말씀드리는 겁니다.
그리고 만드시는 서비스가 어떤 성격인지 모르기 때문에 일반적인 상황을 가정하고 말씀드린 것이니
제가 말한 것들 중 상황에 맞지 않은 부분들에 대한 언급은 양해 부탁드립니다.

1개의 좋아요

우선은 테스트 중이라 괜찮을 것 같습니다.
참고할만한 코드를 전달해주시면 제가 공부하는데 도움이 될 것 같습니다.

getCoordsForEachAddr 라는 이름으로 구현했습니다.
data 에는 주소 문자열들이 들어있는 배열을 넣어주시면 됩니다.
bunchSize 는 [한 번에 연속적으로 호출할 갯수] 입니다. 아래 테스트에서는 300개로 지정했습니다.
oncomplete 는 모든 요청이 끝났을 때, 그 동안 수집한 좌표들을 배열을 넘겨주는 콜백 함수를 받습니다.
결과로 받는 좌표의 배열은 Array.<{lat:Number, lng:Number}> 타입을 가지며
결과 인덱스는 입력 배열(주소) 인덱스와 매핑되도록 맞췄습니다.

1444개의 데이터 셋을 가지고 실행한 결과
총 9초에 걸쳐 모두 문제없이 로딩 되었으며
타이틀이 적용된 마커가 모두 정상적으로 찍혀있는 것을 확인했습니다.

해당 코드는 버그가 있을 수 있으며, 모든 상황에 대응하는 예외처리는 되어 있지 않습니다.
더 좋은 방법이 있을 수 있으니 참고만 해주세요.

function getCoordsForEachAddr (data, bunchSize, oncomplete) {               
                                                                            
    var geocoder = new daum.maps.services.Geocoder();                       
    var tryCount = 0;                                                       
    var doneCount = 0;                                                      
    var totalSize = data.length;                                            
    var coordArray = [];                                                    
                                                                            
    function indexedCallback (index) {                                      
                                                                            
        return function (status, result) {                                  
                                                                            
            doneCount++;                                                    
                                                                            
            if (status === daum.maps.services.Status.OK) {                  
                                                                            
                var addr = result.addr[0];                                  
                                                                            
                coordArray[index] = {                                       
                    'lat': addr.lat,                                        
                    'lng': addr.lng                                         
                };                                                          
   
            } else {

                coordArray[index] = null;
            }                                                               
                                                                            
            if (doneCount === totalSize) {                                  
                                                                            
                oncomplete(coordArray);                                     
                                                                            
            } else if (doneCount === tryCount * bunchSize) {          
                                                                                                                                        
                doRequest();                                                
            }                                                               
        };                                                                  
    }                                                                       
                                                                            
    function doRequest () {                                                 
                                                                            
        var i = doneCount,                                                  
            len = Math.min(totalSize, i + bunchSize);                  
     
        tryCount++;
                                                                            
        for (; i < len; i++) {                                              
            geocoder.addr2coord(data[i], indexedCallback(i));               
        }                                                                   
    }                                                                       
                                                                            
    doRequest();                                                            
}                                                                           
                                                                            
function test () {                                                          
                                                                            
    getCoordsForEachAddr(addrs, 300, function(data) {                       
                                                                            
        data.forEach(function(coord, i) {                                   
                                                                            
            if (!coord) {              
                                 
                return;                                                     
            }                                                               
                                                                            
            new daum.maps.Marker({                                          
                map: map,                                                   
                title: addrs[i],                                            
                position: new daum.maps.LatLng(coord.lat, coord.lng)        
            });                                                             
        });                                                                 
    });                                                                     
}