Lựa chọn hiệu quả các hồ sơ liên quan bằng ArcPy?


14

Dưới đây là mã tôi đang sử dụng để sao chép nút "bảng liên quan" trong ArcMap. Trong ArcMap, nút đó chọn các tính năng trong một lớp tính năng hoặc bảng dựa trên lựa chọn các tính năng trong một lớp hoặc bảng tính năng liên quan khác.

Trong ArcMap, tôi có thể sử dụng nút đó để "đẩy" lựa chọn của mình sang bảng liên quan trong vài giây. Tôi không thể tìm thấy bất cứ thứ gì được tích hợp trong arcpy sao chép nút này vì vậy tôi đã sử dụng một số vòng lặp lồng nhau để thực hiện cùng một nhiệm vụ.

Mã dưới đây lặp qua bảng "phương pháp điều trị". Đối với mỗi điều trị, nó lặp qua một danh sách "cây". Khi một kết quả khớp được tìm thấy giữa các trường xử lý ID và cây, một lựa chọn xảy ra trong lớp cây. Khi một kết quả khớp được tìm thấy để xử lý, mã không tiếp tục tìm kiếm lớp cây để tìm các kết quả khớp bổ sung. Nó quay trở lại bảng điều trị, chọn điều trị tiếp theo và tìm kiếm lại thông qua lớp tính năng cây.

Mã này hoạt động tốt, nhưng nó chậm chạp. "Bảng điều trị" trong trường hợp này có 16.000 hồ sơ. Lớp tính năng "cây" có 60.000 bản ghi.

Có cách nào khác hiệu quả hơn để tạo lại những gì ESRI đang làm khi nó đẩy lựa chọn từ bảng này sang bảng khác không? Tôi có nên tạo một chỉ mục cho các bảng không? LƯU Ý: Dữ liệu này được lưu trữ trong 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
Bạn đang sử dụng ArcGIS 10.1? Nếu vậy, arcpy.da.SearchCthon có thể sẽ nhanh hơn nhiều (có thể là 10 lần) so với arcpy.SearchCoder. Ngoài ra, bạn có thể muốn xem xét việc sử dụng từ điển Python. Tôi nghi ngờ rằng một "lựa chọn keyfile" như thế này có thể được hưởng lợi rất nhiều từ cách tiếp cận được sử dụng ở đây
PolyGeo

Là cơ sở dữ liệu SDE của bạn trên Oracle một cách tình cờ?
blah238

Câu trả lời:


12

Trước hết, có, bạn chắc chắn sẽ muốn đảm bảo các trường khóa chính và khóa ngoài của bạn được lập chỉ mục trên cả hai bảng. Điều này cho phép DBMS lập kế hoạch và thực hiện các truy vấn đối với các trường này hiệu quả hơn nhiều.

Thứ hai, bạn đang gọi SelectLayerByAttribute_managementtrong một vòng lặp chặt chẽ, lồng nhau (một lần trên mỗi cây cho mỗi điều trị). Điều này rất không hiệu quả, vì nhiều lý do:

  • Bạn không cần hai vòng lặp, một vòng lồng vào nhau, vì điều này, theo như tôi có thể nói. Một người sẽ đủ.
  • Các hàm xử lý địa lý là "chunky" và mất rất nhiều thời gian để gọi so với các hàm Python tích hợp thông thường. Bạn nên tránh gọi họ trong một vòng lặp chặt chẽ.
  • Yêu cầu một bản ghi / ID tại một thời điểm sẽ dẫn đến nhiều chuyến đi vòng tới cơ sở dữ liệu.

Thay vào đó, hãy cấu trúc lại mã của bạn để bạn gọi SelectLayerByAttribute_managementchỉ một lần với một bản khai được xây dựng để chọn tất cả các bản ghi liên quan.

Mượn một chức năng từ một câu trả lời khác cho logic xây dựng nguyên nhân, tôi tưởng tượng nó sẽ trông giống như thế này:

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)

Bạn có thể gọi nó như vậy: selectRelatedRecords(treatment_tv, tree_fl, "Facility_ID", "FACILITYID")

Ghi chú:

  • Điều này sử dụng một arcpy.da.SearchCursor, chỉ có sẵn tại 10.1. Như @PolyGeo đã đề cập, những con trỏ này nhanh hơn nhiều so với người tiền nhiệm của chúng ( arcpy.SearchCursor). Nó có thể dễ dàng được sửa đổi để sử dụng SearchCoder cũ:

    sourceIDs = set([row.getValue(sourceField) for row in arcpy.SearchCursor(sourceLayer, "", "", sourceField)])
  • Nếu cơ sở dữ liệu địa lý SDE của bạn nằm trên Oracle, hãy cảnh báo rằng INcâu lệnh được sử dụng trong hàm từ câu trả lời được liên kết bị giới hạn ở 1000 phần tử. Một giải pháp khả thi được mô tả trong câu trả lời này , nhưng bạn phải sửa đổi hàm để chia nó thành nhiều INcâu lệnh dài 1000 thay vì một câu lệnh.


5

Các giải pháp trên làm việc tuyệt vời cho tôi và rất nhanh chóng. Sử dụng mã ở trên và mã được tham chiếu từ bài đăng khác, đây là cách tôi xây dựng nó:

# 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)
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.