ArcPy를 사용하여 관련 레코드를 효율적으로 선택 하시겠습니까?


14

다음은 ArcMap에서 "관련 테이블"버튼을 복제하는 데 사용하는 코드입니다. ArcMap에서이 버튼은 다른 관련 피쳐 클래스 또는 테이블에서 피쳐 선택을 기반으로 한 피쳐 클래스 또는 테이블에서 피쳐를 선택합니다.

ArcMap에서이 버튼을 사용하여 몇 초 안에 선택한 항목을 관련 테이블로 "밀어 넣을 수 있습니다". 버튼을 복제하는 arcpy에 내장 된 것을 찾을 수 없으므로 동일한 루프를 사용하여 동일한 작업을 수행했습니다.

아래 코드는 "치료"표를 반복합니다. 각 처리에 대해 "트리"목록을 반복합니다. 트리트먼트의 ID 필드와 트리간에 일치하는 것이 있으면 트리 레이어에서 선택이 이루어집니다. 처리에 대한 일치가 발견되면 코드는 트리 계층에서 추가 일치를 계속 검색하지 않습니다. 처리 테이블로 돌아가 다음 처리를 선택하고 트리 피쳐 클래스를 다시 검색합니다.

코드 자체는 잘 작동하지만 느리게 느립니다. 이 경우 "치료 테이블"에는 16,000 개의 레코드가 있습니다. "트리"피처 클래스에는 60,000 개의 레코드가 있습니다.

ESRI가 한 테이블에서 다른 테이블로 선택을 푸시 할 때 수행하는 작업을 다시 작성하는 또 다른 효율적인 방법이 있습니까? 테이블에 대한 인덱스를 작성해야합니까? 참고 :이 데이터는 SDE에 저장됩니다.

 # Create search cursor to loop through the treatments
treatments = arcpy.SearchCursor(treatment_tv)
treatment_field = "Facility_ID"

for treatment in treatments:

    #Get ID of treatment
    treatment_ID = treatment.getValue(treatment_field)

    # Create search cursor for looping through the trees
    trees = arcpy.SearchCursor(tree_fl)
    tree_field = "FACILITYID"

    for tree in trees:

        # Get FID of tree
        tree_FID = tree.getValue(tree_field)

        if tree_FID == treatment_FID:
            query = "FACILITYID = " + str(tree_FID)
            arcpy.SelectLayerByAttribute_management(tree_fl, "REMOVE_FROM_SELECTION", query)
            break

2
ArcGIS 10.1을 사용하고 있습니까? 그렇다면 arcpy.da.SearchCursor가 arcpy.SearchCursor보다 훨씬 빠를 것입니다 (아마도 10X). 또한 파이썬 사전의 사용을 고려할 수도 있습니다. 나는 접근 방식이 사용에서이 같은 "키 파일 선택"크게 도움이 의심 여기
PolyGeo

SDE 데이터베이스가 Oracle에 우연히 있습니까?
blah238

답변:


12

우선, 기본 및 외래 키 필드가 두 테이블 모두에서 색인화되도록해야합니다. 이를 통해 DBMS는 이러한 필드에 대해 훨씬 효율적으로 쿼리를 계획하고 실행할 수 있습니다.

두 번째로, SelectLayerByAttribute_management꽉 중첩 된 루프 (처리 당 트리 당 한 번)를 호출 합니다. 여러 가지 이유로 매우 비효율적입니다.

  • 내가 알 수있는 한 두 개의 루프가 필요하지 않습니다. 하나는 다른 루프 안에 중첩되어 있습니다. 충분할 것입니다.
  • 지오 프로세싱 함수는 "고정적"이며 일반적인 내장 Python 함수에 비해 호출하는 데 많은 시간이 걸립니다. 꽉 조여서 호출하지 않아야합니다.
  • 한 번에 하나의 레코드 / ID를 요청하면 데이터베이스를 훨씬 더 많이 왕복 할 수 있습니다.

대신, SelectLayerByAttribute_management모든 관련 레코드를 선택하도록 whereclause로 한 번만 호출하도록 코드를 리팩토링하십시오 .

whereclause 구성 논리에 대한 다른 답변 에서 함수를 빌리면 다음과 같이 보일 것입니다.

def selectRelatedRecords(sourceLayer, targetLayer, sourceField, targetField):
    sourceIDs = set([row[0] for row in arcpy.da.SearchCursor(sourceLayer, sourceField)])
    whereClause = buildWhereClauseFromList(targetLayer, targetField, sourceIDs)
    arcpy.AddMessage("Selecting related records using WhereClause: {0}".format(whereClause))
    arcpy.SelectLayerByAttribute_management(targetLayer, "NEW_SELECTION", whereClause)

다음과 같이 호출 할 수 있습니다. selectRelatedRecords(treatment_tv, tree_fl, "Facility_ID", "FACILITYID")

노트:

  • arcpy.da.SearchCursor10.1에서만 사용 가능한을 사용합니다 . @PolyGeo가 언급했듯이이 커서는 이전 커서 ( arcpy.SearchCursor) 보다 훨씬 빠릅니다 . 그래도 이전 SearchCursor를 사용하도록 쉽게 수정할 수 있습니다.

    sourceIDs = set([row.getValue(sourceField) for row in arcpy.SearchCursor(sourceLayer, "", "", sourceField)])
  • SDE 지오 데이터베이스가 Oracle에있는 IN경우 링크 된 답변의 함수에 사용 된 명령문이 1000 개 요소로 제한됩니다. 하나의 가능한 해결책 이이 답변에 설명되어 있지만 함수를 수정하여 IN하나가 아닌 여러 1000 길이의 문 으로 나누어야합니다 .


5

위의 솔루션은 저에게 효과적이며 매우 빠릅니다. 위의 코드와 다른 게시물의 참조 코드를 사용하면 이것이 내가 작성한 방법입니다.

# Local Variables
OriginTable = "This must be a Table View or Feature Layer"
DestinationTable = "This must be a Table View or Feature Layer"
PrimaryKeyField = "Matching Origin Table Field"
ForiegnKeyField = "Matching Destination Table Field"

def buildWhereClauseFromList(OriginTable, PrimaryKeyField, valueList):
  """Takes a list of values and constructs a SQL WHERE
       clause to select those values within a given PrimaryKeyField
       and OriginTable."""

    # Add DBMS-specific field delimiters
    fieldDelimited = arcpy.AddFieldDelimiters(arcpy.Describe(OriginTable).path, PrimaryKeyField)

    # Determine field type
    fieldType = arcpy.ListFields(OriginTable, PrimaryKeyField)[0].type

    # Add single-quotes for string field values
    if str(fieldType) == 'String':
    valueList = ["'%s'" % value for value in valueList]

    # Format WHERE clause in the form of an IN statement
    whereClause = "%s IN(%s)" % (fieldDelimited, ', '.join(map(str, valueList)))
    return whereClause

def selectRelatedRecords(OriginTable, DestinationTable, PrimaryKeyField, ForiegnKeyField):
    """Defines the record selection from the record selection of the OriginTable
      and applys it to the DestinationTable using a SQL WHERE clause built
      in the previous defintion"""

    # Set the SearchCursor to look through the selection of the OriginTable
    sourceIDs = set([row[0] for row in arcpy.da.SearchCursor(OriginTable, PrimaryKeyField)])

    # Establishes the where clause used to select records from DestinationTable
    whereClause = buildWhereClauseFromList(DestinationTable, ForiegnKeyField, sourceIDs)

    # Process: Select Layer By Attribute
    arcpy.SelectLayerByAttribute_management(DestinationTable, "NEW_SELECTION", whereClause)

# Process: Select related records between OriginTable and DestinationTable
selectRelatedRecords(OriginTable, DestinationTable, PrimaryKeyField, ForiegnKeyField)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.