Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
389 changes: 389 additions & 0 deletions scripts/generate-load-test-data.sql

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Address() : ModifiableAuditableEntity() {
var uprn: Long? = null
private set

@Column(nullable = false, length = 1000)
@Column(nullable = false, length = SINGLE_LINE_ADDRESS_LENGTH)
lateinit var singleLineAddress: String
private set

Expand Down Expand Up @@ -77,4 +77,8 @@ class Address() : ModifiableAuditableEntity() {
}

fun getSelectedAddress(): String = if (uprn == null) MANUAL_ADDRESS_CHOSEN else singleLineAddress

companion object {
const val SINGLE_LINE_ADDRESS_LENGTH = 1000
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import jakarta.persistence.OneToMany
import jakarta.persistence.OneToOne
import uk.gov.communities.prsdb.webapp.constants.enums.OccupancyType
import uk.gov.communities.prsdb.webapp.constants.enums.OwnershipType
import uk.gov.communities.prsdb.webapp.database.entity.Address.Companion.SINGLE_LINE_ADDRESS_LENGTH
import java.time.LocalDate

@Entity
Expand Down Expand Up @@ -60,6 +61,10 @@ class PropertyOwnership() : ModifiableAuditableEntity() {
@JoinColumn(name = "incomplete_compliance_form_id", nullable = true, unique = true)
var incompleteComplianceForm: FormContext? = null

@Column(nullable = false, insertable = false, updatable = false, length = SINGLE_LINE_ADDRESS_LENGTH)
lateinit var singleLineAddress: String
private set

@OneToMany(mappedBy = "propertyOwnership", orphanRemoval = true)
var certificateUploads: MutableSet<CertificateUpload> = mutableSetOf()
private set
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,10 @@ interface PropertyOwnershipRepository : JpaRepository<PropertyOwnership, Long> {
@Query(
"SELECT po.* " +
"FROM property_ownership po " +
"JOIN property p ON po.property_id = p.id " +
"JOIN address a ON p.address_id = a.id " +
"WHERE po.is_active AND a.single_line_address %> :searchTerm " +
"WHERE po.single_line_address %>> :searchTerm " +
"AND po.is_active " +
FILTERS +
"ORDER BY a.single_line_address <->> :searchTerm",
"ORDER BY po.single_line_address <->>> :searchTerm",
nativeQuery = true,
)
fun searchMatching(
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ spring:
password: ${RDS_PASSWORD}

hikari:
connection-init-sql: SET pg_trgm.word_similarity_threshold = 0.2
connection-init-sql: SET pg_trgm.strict_word_similarity_threshold = 0.6;

jpa:
hibernate:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
ALTER TABLE property_ownership
ADD single_line_address VARCHAR(1000) DEFAULT '' NOT NULL;

UPDATE property_ownership po SET single_line_address = (
SELECT a.single_line_address
FROM address a
JOIN property p ON a.id = p.address_id
WHERE p.id = po.property_id
);

CREATE FUNCTION update_property_ownership_single_line_address()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
DECLARE
propertyOwnershipId BIGINT;
propertyId BIGINT;
addressId BIGINT;
BEGIN
CASE
WHEN TG_TABLE_NAME = 'property_ownership' THEN
propertyOwnershipId := NEW.id;
UPDATE property_ownership po SET single_line_address = (
SELECT a.single_line_address
FROM address a
JOIN property p ON a.id = p.address_id
WHERE p.id = po.property_id
)
WHERE po.id = propertyOwnershipId;

WHEN TG_TABLE_NAME = 'property' THEN
propertyId := NEW.id;
UPDATE property_ownership po SET single_line_address = (
SELECT a.single_line_address
FROM address a
JOIN property p ON a.id = p.address_id
WHERE p.id = property_id
)
WHERE po.property_id = propertyId;

WHEN TG_TABLE_NAME = 'address' THEN
addressId := NEW.id;
UPDATE property_ownership po SET single_line_address = (
SELECT a.single_line_address
FROM address a
WHERE a.id = addressId
)
WHERE po.property_id = (SELECT p.id FROM property p WHERE p.address_id = addressId);
END CASE;
RETURN NULL;
END;
$$;

CREATE TRIGGER insert_property_ownership_single_line_address
AFTER INSERT ON property_ownership
FOR EACH ROW
EXECUTE FUNCTION update_property_ownership_single_line_address();

CREATE TRIGGER update_property_ownership_single_line_address
AFTER UPDATE OF property_id ON property_ownership
FOR EACH ROW
WHEN (OLD.property_id IS DISTINCT FROM NEW.property_id)
EXECUTE FUNCTION update_property_ownership_single_line_address();

CREATE TRIGGER update_property_ownership_single_line_address
AFTER UPDATE OF address_id ON property
FOR EACH ROW
WHEN (OLD.address_id IS DISTINCT FROM NEW.address_id)
EXECUTE FUNCTION update_property_ownership_single_line_address();

CREATE TRIGGER update_property_ownership_single_line_address
AFTER UPDATE OF single_line_address ON address
FOR EACH ROW
WHEN (OLD.single_line_address IS DISTINCT FROM NEW.single_line_address)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this approach not massively slow down the seeding of the DB with NGD address data?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been removed as we'll be referencing property ownerships from addresses rather than the other way around

Copy link
Contributor Author

@isobel-softwire isobel-softwire Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, querying the address table is much slower than querying the property ownership table, even with a partial index. I'll go back to referencing addresses from property ownerships. To combat slowing down NGD data loading, we can refresh the addresses once after loading finishes, rather than using this trigger.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intrigued that it takes longer - would expect it to be at least similar - but yes, if we can update them for each batch in one go during ingest instead of using the trigger that should at least limit the slow-down there

EXECUTE FUNCTION update_property_ownership_single_line_address();

CREATE INDEX property_ownership_single_line_address_idx ON property_ownership USING gist (single_line_address gist_trgm_ops(siglen=2024)) WHERE is_active;
Original file line number Diff line number Diff line change
Expand Up @@ -258,11 +258,11 @@ class SearchRegisterTests : IntegrationTestWithImmutableData("data-search.sql")
@Test
fun `Fuzzy search produces table of matching results`(page: Page) {
val searchPropertyRegisterPage = navigator.goToPropertySearchPage()
searchPropertyRegisterPage.searchBar.search("Way")
searchPropertyRegisterPage.searchBar.search("Fake Way")
val resultTable = searchPropertyRegisterPage.resultTable

assertThat(resultTable.getCell(0, PROPERTY_COL_INDEX)).containsText("3 Fake Way")
assertThat(resultTable.getCell(1, PROPERTY_COL_INDEX)).containsText("5 Pretend Crescent Way")
assertThat(resultTable.getCell(1, PROPERTY_COL_INDEX)).containsText("5 Fake Crescent Way")
}

@Test
Expand Down
2 changes: 1 addition & 1 deletion src/test/resources/data-search.sql
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ VALUES (1, '09/13/24', '09/13/24', 1, '1 Fictional Road', 1, 'AA1 1AA'),
(7, '09/13/24', '09/13/24', 6, '2 Fictional Road', 1, 'AA1 1AF'),
(8, '09/13/24', '09/13/24', 7, '3 Fake Way', 2, 'AA1 1AG'),
(9, '09/13/24', '09/13/24', 8, '4 Imaginary Street', 1, 'AA1 1AH'),
(10, '09/13/24', '09/13/24', 9, '5 Pretend Crescent Way', 1, 'AA1 1AJ'),
(10, '09/13/24', '09/13/24', 9, '5 Fake Crescent Way', 1, 'AA1 1AJ'),
(11, '09/13/24', '09/13/24', 10, '6 Mythical Place', 1, 'AA1 1AK'),
(12, '09/13/24', '09/13/24', null, '6 Mythical Place', 1, 'AA1 1AL'),
(13, '05/02/25', '05/02/25', 1013, '1 PRSDB Square, EG1 2AA', 1, 'EG1 2AA'),
Expand Down
Loading