Memilih catatan terkait secara efisien menggunakan ArcPy?

14

Di bawah ini adalah kode yang saya gunakan untuk mereplikasi tombol "tabel terkait" di ArcMap. Di ArcMap tombol itu memilih fitur dalam satu kelas fitur atau tabel berdasarkan pemilihan fitur di kelas atau tabel fitur terkait lainnya.

Di ArcMap saya dapat menggunakan tombol itu untuk "mendorong" pilihan saya ke tabel terkait dalam hitungan detik. Saya tidak dapat menemukan apa pun yang ada di dalam untuk arcpy yang mereplikasi tombol jadi saya menggunakan beberapa loop bersarang untuk melakukan tugas yang sama.

Kode di bawah ini loop melalui tabel "perawatan". Untuk setiap perawatan, itu loop melalui daftar "pohon". Ketika kecocokan ditemukan antara bidang ID pengobatan dan pohon, pilihan terjadi di lapisan pohon. Setelah kecocokan ditemukan untuk perawatan, kode tidak melanjutkan mencari lapisan pohon untuk kecocokan tambahan. Itu kembali ke tabel perawatan, memilih perawatan berikutnya dan lagi mencari melalui kelas fitur pohon.

Kode itu sendiri berfungsi dengan baik, tetapi lambat sekali. "Tabel perawatan" dalam kasus ini memiliki 16.000 catatan. Kelas fitur "tree" memiliki 60.000 catatan.

Apakah ada cara lain yang lebih efisien untuk menciptakan kembali apa yang dilakukan ESRI ketika mendorong seleksi dari satu meja ke meja lainnya? Haruskah saya membuat indeks untuk tabel? CATATAN: Data ini disimpan dalam 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
WatsonP
sumber
2
Apakah Anda menggunakan ArcGIS 10.1? Jika demikian, arcpy.da.SearchCursor kemungkinan jauh lebih cepat (mungkin 10X) daripada arcpy.SearchCursor. Juga, Anda mungkin ingin mempertimbangkan penggunaan kamus Python. Saya menduga bahwa "pemilihan keyfile" seperti ini mungkin sangat bermanfaat dari pendekatan yang digunakan di sini
PolyGeo
Apakah basis data SDE Anda di Oracle kebetulan?
blah238

Jawaban:

12

Pertama, ya Anda pasti ingin memastikan bidang kunci utama dan asing Anda diindeks di kedua tabel. Ini memungkinkan DBMS merencanakan dan menjalankan kueri terhadap bidang-bidang ini dengan lebih efisien.

Kedua, Anda memanggil SelectLayerByAttribute_managementlingkaran ketat, bersarang (sekali per pohon per perawatan). Ini sangat tidak efisien, karena beberapa alasan:

  • Anda tidak perlu dua loop, satu bersarang di dalam yang lain, untuk ini, sejauh yang saya tahu. Satu sudah cukup.
  • Fungsi-fungsi geoproses adalah "chunky" dan membutuhkan banyak waktu untuk menelepon dibandingkan dengan fungsi-fungsi Python bawaan. Anda harus menghindari memanggil mereka dalam lingkaran yang ketat.
  • Meminta satu catatan / ID pada suatu waktu menghasilkan perjalanan jauh lebih jauh ke database.

Alih-alih, perbaiki kode Anda sehingga Anda menelepon SelectLayerByAttribute_managementsekali saja dengan alasan dibangun untuk memilih semua catatan terkait.

Meminjam fungsi dari jawaban lain untuk logika konstruksi karena itu, saya membayangkan itu akan terlihat seperti ini:

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)

Anda bisa menyebutnya seperti ini: selectRelatedRecords(treatment_tv, tree_fl, "Facility_ID", "FACILITYID")

Catatan:

  • Ini menggunakan arcpy.da.SearchCursor, hanya tersedia di 10.1. Seperti @PolyGeo sebutkan, kursor ini jauh lebih cepat dari pendahulunya ( arcpy.SearchCursor). Itu bisa dengan mudah dimodifikasi untuk menggunakan SearchCursor lama:

    sourceIDs = set([row.getValue(sourceField) for row in arcpy.SearchCursor(sourceLayer, "", "", sourceField)])
  • Jika geodatabase SDE Anda menggunakan Oracle, berhati-hatilah bahwa INpernyataan yang digunakan dalam fungsi dari jawaban yang ditautkan terbatas pada 1000 elemen. Satu solusi yang mungkin dijelaskan dalam jawaban ini , tetapi Anda harus memodifikasi fungsi untuk membaginya menjadi beberapa INpernyataan panjang 1000 bukannya satu.

blah238
sumber
5

Solusi di atas berfungsi baik untuk saya dan sangat cepat. Menggunakan kode di atas dan kode referensi dari posting lain ini adalah bagaimana saya membangunnya:

# 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)
pengguna1714326
sumber