When I apply patch #48 from issue 2007692 to 1.17 version, the deeper levels of entity references are not being re-indexed.

I have a site using group/group content module and there are different indexes for each group content bundle. The indexes contain group content entities. Group content relates to nodes. Nodes can relate to taxonomies and other nodes via entity references.

For example:

  • Employers index: indexes group content of Employer node
    • advertiser_name => entity_id:entity:field_advertiser_name => Group content > Employer node > Advertiser name field
  • Opportunities index: indexes group content of Opportunity node
    • parent_employer_advertiser_name => entity_id:entity:field_parent_employer:entity:field_advertiser_name => Group Content > Opportunity node > Field parent employer references Employers > Employer node > Advertiser name field
  • Events index: indexes group content of Event node
    • organisation_alternative_name => entity_id:entity:field_organisation_name:entity:field_advertiser_name => Group content > Event node > Organisation name field references Employers > Employer node > Advertiser name

When I update the Advertiser name field, I would expect that all references (Employers, Opportunities and Events) would be reindexed. However, only the Employer index gets the update.

Comments

carolpettirossi created an issue. See original summary.

carolpettirossi’s picture

I think the issue is related to a wrong map being generated on getForeignEntityRelationsMap

After some debugging I've noticed that if I remove $relation_info['entity_type'] !== $entity_reference['entity_type'] from the code below, the re-index start to work.

$entity_reference = $this->isEntityReferenceDataDefinition($property_definition, $cacheability);
if ($entity_reference
    && $relation_info['entity_type'] !== $entity_reference['entity_type']) {
  $relation_info = $entity_reference;
  $relation_info['property_path_to_foreign_entity'] = implode(IndexInterface::PROPERTY_PATH_SEPARATOR, $seen_path_chunks);
}

@borisson_ suggested raising a separate issue to attach a new patch and run the tests.

Here's the thread where we've been discussing the issue: https://drupal.slack.com/archives/C34CECZAL/p1603295848130200

borisson_’s picture

Status: Active » Needs review

It looks like we either do not have sufficient test-coverage or this change did not make an impact on them. But from the anecdotal evidence provided by @carolpettirossi this change makes sense.

I would love to have more testcoverage for this, but i'm not sure how much this will get us, because setting up that scenario is really complicated.
I'd love to get feedback from drunken monkey on this before moving this to rtbc.

kyuubi’s picture

Hi everyone,

As usual thank you for the incredible hard work on this amazing platform that is Search API.

I'd like to take this issue to express some concerns with the approach already committed to Search API in https://www.drupal.org/project/search_api/issues/2007692

The main problem is this: when we start baking in logic in regards to index invalidation on entity save, we need to consider scenarios where there are a LOT of dependent entities being saved. This means an entity save will eventually (on sufficient large sites) lead to a timeout or memory exhaustion.

Before this patch I was thinking of implementing this as a queue based system (which makes sense in our case) as, for us, an entity save can lead up to 10k index items changing or more (for example a change in a taxonomy term). This means we can take the Search API "we don't deal with this is too complex" approach (that I personally agree with) and bake in a solution for our specific problem.

With this now committed I'm concerned about the potential ramifications for sites like ours and more importantly how we can deal with this in order to stay compatible with Search API's new approach.

Hope this makes sense and looking forward to hear your thoughts!

carolpettirossi’s picture

Hi guys,

The timeout issue does occur in cases you have a large database with different indexes and lots of content entities.
For example, in my case, when I update a Degree Type taxonomy term that relates to around 80k entities it takes more than 40s for the page to save. This behavior on localhost is fine, however on an environment with 30s timeout that would error out.

I added code to measure getAffectedItemsForEntityChange and analyse how long $entity_ids = array_values($query->execute()); and the foreach block takes to execute and here is the output:

Anabranch Connect Index: Query time is: 0.022436141967773 seconds
Anabranch Connect Index: Foreach time is: 9.5367431640625E-7 secondsentity:group_content
Anabranch Connect Index: Query time is: 0.0022249221801758 seconds
Anabranch Connect Index: Foreach time is: 2.1457672119141E-6 secondsentity:group_content
Anabranch Connect Index: Query time is: 0.70239186286926 seconds
Anabranch Connect Index: Foreach time is: 4.6936919689178 secondsentity:group_content
Anabranch Connect Index: Query time is: 0.75657796859741 seconds
Anabranch Connect Index: Foreach time is: 5.0897030830383 secondsentity:group_content
Anabranch Connect Index: Query time is: 0.00897216796875 seconds
Anabranch Connect Index: Foreach time is: 0.011008977890015 secondsentity:group_content
Anabranch Connect Index: Query time is: 0.0016090869903564 seconds
Anabranch Connect Index: Foreach time is: 1.9073486328125E-6 secondsentity:group_content
Anabranch Connect Index: Query time is: 0.0016870498657227 seconds
Anabranch Connect Index: Query time is: 0.0022618770599365 seconds
Anabranch Connect Index: Query time is: 0.0014770030975342 seconds
Anabranch Connect Index: Query time is: 0.0016851425170898 seconds
Anabranch Connect Index: Query time is: 0.0016920566558838 seconds
Anabranch Connect Index: Query time is: 0.0030779838562012 seconds
Anabranch Connect Index: Foreach time is: 2.8610229492188E-6 secondsentity:group_content
Anabranch Connect Index: Query time is: 0.0025160312652588 seconds
Anabranch Connect Index: Query time is: 0.0022759437561035 seconds
Anabranch Connect Index: Query time is: 0.001176118850708 seconds

Article index: Query time is: 0.0018000602722168 seconds
Article index: Foreach time is: 3.0994415283203E-6 secondsentity:group_content
Article index: Query time is: 0.0027029514312744 seconds
Article index: Foreach time is: 2.1457672119141E-6 secondsentity:group_content
Article index: Query time is: 0.001784086227417 seconds
Article index: Query time is: 0.0018301010131836 seconds
Article index: Query time is: 0.0014579296112061 seconds
Article index: Foreach time is: 1.9073486328125E-6 secondsentity:group_content

Career opportunity index: Query time is: 0.0017669200897217 seconds
Career opportunity index: Foreach time is: 3.0994415283203E-6 secondsentity:group_content
Career opportunity index: Query time is: 0.001643180847168 seconds
Career opportunity index: Foreach time is: 1.9073486328125E-6 secondsentity:group_content
Career opportunity index: Query time is: 0.0016598701477051 seconds
Career opportunity index: Query time is: 0.0016038417816162 seconds

Course index: Query time is: 0.77181386947632 seconds
Course index: Foreach time is: 5.2628490924835 secondsentity:group_content
Course index: Query time is: 0.6846559047699 seconds
Course index: Foreach time is: 4.9171540737152 secondsentity:group_content
Course index: Query time is: 0.0065701007843018 seconds
Course index: Foreach time is: 2.8610229492188E-6 secondsentity:group_content
Course index: Query time is: 0.001978874206543 seconds
Course index: Foreach time is: 1.9073486328125E-6 secondsentity:group_content

Employer index: Query time is: 0.0012490749359131 seconds
Employer index: Foreach time is: 1.9073486328125E-6 secondsentity:group_content
Employer index: Query time is: 0.0016818046569824 seconds
Employer index: Query time is: 0.0014750957489014 seconds
Employer index: Foreach time is: 4.0531158447266E-6 secondsentity:group_content
Employer index: Query time is: 0.0014309883117676 seconds
Employer index: Foreach time is: 2.1457672119141E-6 secondsentity:group_content
Employer index: Query time is: 0.0015189647674561 seconds
Employer index: Query time is: 0.0051629543304443 seconds
Employer index: Foreach time is: 2.2172927856445E-5 secondsentity:group_content

Event index: Query time is: 0.0016829967498779 seconds
Event index: Foreach time is: 1.9073486328125E-6 secondsentity:group_content
Event index: Query time is: 0.0017240047454834 seconds
Event index: Query time is: 0.0015909671783447 seconds
Event index: Foreach time is: 2.1457672119141E-6 secondsentity:group_content
Event index: Query time is: 0.0016031265258789 seconds

Institution index: Query time is: 0.0016078948974609 seconds
Institution index: Foreach time is: 2.1457672119141E-6 secondsentity:group_content

Scholarship index: Query time is: 0.007498025894165 seconds
Scholarship index: Foreach time is: 0.012362003326416 secondsentity:group_content
Scholarship index: Query time is: 0.0018000602722168 seconds
Scholarship index: Foreach time is: 3.0994415283203E-6 secondsentity:group_content
Scholarship index: Query time is: 0.0028719902038574 seconds

Story index: Query time is: 0.0017101764678955 seconds
Story index: Foreach time is: 3.0994415283203E-6 secondsentity:group_content
Story index: Query time is: 0.001784086227417 seconds
Story index: Foreach time is: 1.9073486328125E-6 secondsentity:group_content
Story index: Query time is: 0.0015840530395508 seconds

As you can see the "Anabranch Connect index" has more term references and that's why there are more queries being executed there. The time to execute the query doesn't seem a huge issue. However, if you sum up the queries and loops time spent that is definitely something to be considered.

I also noticed that even if I disable "Anabranch Connect index", getAffectedItemsForEntityChange considers/runs for it.

borisson_’s picture

I saw your post yesterday @kyuubi, thanks for adding another voice in this discussion.
Also a huge thanks for those numbers @carolpettirossi - those are really helpful.

So it seems like there are 3 paths forward.

  1. Ensure that this code works more better with more performance.
  2. Remove this behavior again.
  3. Put it behind a checkbox.

I think trying the first option is going to be a whole lot of work so I personally would prefer we do this with a checkbox that is enabled by default.

kyuubi’s picture

Hi @borisson_,

Thank you very much for the quick feedback.

I think 1, realistically is always going to be tough to achieve generically. I imagine this is why Search API has historically steered away from this problem, due to the amount of possibilities and use cases.

I also think removing 2 is a shame, because realistically I'd imagine for more than 50% of sites out there, the current solution will be totally fine (unfortunately that's not our case).

Option 3 seems like a simple and very effective way to offer a good out of the box solution, with well disclaimed caveats.

So, I'd propose:

  1. Add a feature flag for this (checkbox)
  2. Add a warning/disclaimer informing the user of the potential performance implications on large sites with many references (not unlike the "index immediately" situation)

Would that work for everyone?

Thanks again!

borisson_’s picture

  1. Add a feature flag for this (checkbox)
  2. Add a warning/disclaimer informing the user of the potential performance implications on large sites with many references (not unlike the "index immediately" situation)

This sounds like great solution, +1!

carolpettirossi’s picture

Title: Changes in related entities are not being re-indexed for all levels of entity references » Changes in related entities are not being re-indexed for all levels of entity references and performance issues in large sites
StatusFileSize
new5.19 KB

Thank you so much for the suggestions @borisson_.

I've created a patch adding the checkbox to index options and ignoring the indexes with the option disabled in trackReferencedEntityUpdate. I also implemented a hook_update to enable this option in all existing indexes by default.

It would be great if you or someone from the community validate this patch so we can get it pushed hopefully in the next search_api release.

fenstrat’s picture

Status: Needs review » Reviewed & tested by the community
StatusFileSize
new5.18 KB
new515 bytes

Agreed that a kill switch toggle like this is needed as the performance implications are pretty intense.

Tentatively setting this at RTBC, only bit I'm unsure on is the $relation_info['entity_type'] !== $entity_reference['entity_type'] change.

Attached is a simple re-roll of #10 to fix a whitespace issue.

sam152’s picture

There is an open bug for how the relationship info is applied to the calculation of related entities: #3178941: Fatal error "Call to a member function getColumns() on bool". Perhaps the bug report in #2 is related to or fixed by that?

+++ b/src/Utility/TrackingHelper.php
@@ -212,8 +217,7 @@ class TrackingHelper implements TrackingHelperInterface {
-        if ($entity_reference
-            && $relation_info['entity_type'] !== $entity_reference['entity_type']) {
+        if ($entity_reference) {

I do agree, these few changes look a little out of place in the current patch.

fenstrat’s picture

StatusFileSize
new4.66 KB
new721 bytes

Agreed that the bug report in #2 does look like #3178941: Fatal error "Call to a member function getColumns() on bool", so removing that from here. Leaving as RTBC.

borisson_’s picture

Looks good to me, +1

drunken monkey’s picture

Status: Reviewed & tested by the community » Needs work

Thanks a lot for reporting this issue, carolpettirossi, for providing the clear analysis and the simple but effective patch. Sorry it took me so long to get back to this, unfortunately I had very little time for contrib work in the past few months.

Anyways, the above just pertains to the first few comments. Starting at #5, I’m not sure what happened.
@ kyuubi/#5: This is a completely different problem! Why did you think it would be a good idea to hijack this issue and make it about your problem instead?
And then, why did everyone else go along with it – in the end even removing the fix for the actual issue reported, without waiting for a reaction from the issue reporter? (I also don’t see how “doesn’t work sometimes for deeper nesting” sounds similar to “I get a fatal error”?)

@ carolpettirossi: Could you please try and test again with the latest dev version of the module (after #3178941: Fatal error "Call to a member function getColumns() on bool")? Is the problem still present, and does your patch (#2) still fix it? (As noted above, I don’t see why the two should be related, but better to verify first.)

kyuubi’s picture

@drunken monkey you are absolutely right, it's actually not related and it was not my intent to deviate things from the original issue.

To clarify, I was actually working on the consequences of this patch with Carol and given it was caused by the linked patch it sort of evolved to "lets fix the issues the patch created" (which are the ones stated in the title). I understand that might not have been the best way to go about it and I apologise.

However given everyone is just trying to help here, maybe we can do away with salty responses for everyone's benefit? I wasn't trying to make it "my problem instead" as I'm literally working on the exact same issue as Carol (we work together). For us they are one problem (caused by the patch) but I can see that wouldn't be the case for a maintainer.

Let me know if you want me to move the issue (and fix patch) to a separate issue and I'll open it up.

Thanks

drunken monkey’s picture

OK, thanks for your apology, kyuubi, and sorry in turn that my response came out a bit harsh. It just seemed very rude to me – I couldn’t know you’re working together on this, which of course changes things. You might have just mentioned it in your comment, to explain why you felt it appropriate to discuss both issues at once.

However, it’s still unclear to me whether the original issue is a) already resolved in HEAD or b) resolved by the latest patch. (Neither seems to be the case, from the looks of it – but would be great to have confirmation.) If neither is the case, then yes, please create a new issue for the performance issue. Otherwise, it seems OK to just continue discussing this here. (Feedback from carolpettirossi in this regard would be great, in case you can ping her.)

carolpettirossi’s picture

Hi @drunken_monkey,

Sorry for the late reply. I've just tested the latest dev version and it seems that the entity references re-indexing is completely broken now?

I couldn't make any of my advertiser_name fields to work.

For reference, I tested only one index with these fields:

- advertiser_name => entity_id:entity:field_advertiser_name
- parent_employer_advertiser_name => entity_id:entity:field_parent_employer:entity:field_advertiser_name
- parent_organisation_advertiser_name => entity_id:entity:field_organisation_name:entity:field_advertiser_name

Expected result:
- When I update field_advertiser_name it should re-index all documents containing references to it and update the advertiser_name, parent_organisation_advertiser_name fields in the documents.

The current result with latest dev version:
- It does not update any related document. When I update the node and check the tracker it remains the same.

I'd like to test some other scenarios with more indexes, but would you like your feedback on why dev might not be working at all first.

Thank you so much for your support with this.

drunken monkey’s picture

Title: Changes in related entities are not being re-indexed for all levels of entity references and performance issues in large sites » Changes in related entities are not being re-indexed for all levels of entity references
Status: Needs work » Needs review
StatusFileSize
new9.01 KB
new10.37 KB

That is very strange indeed. As you’re aware, we have automated test coverage for this functionality, so it’s unlikely this was broken by some new code. Also, I just tested and it works fine for me. Sorry, but I don’t really know why it suddenly stopped working for you.

However, I now tried myself and the problem (and functionality) is easy to reproduce on a new Drupal installation. Just …

  1. add a node reference field to a content type
  2. create a chain of three nodes referencing each other (1 -> 2 -> 3)
  3. add a field two levels down to the search index – for instance, “Node ref » Content » Node ref » Content » Title”
  4. re-index
  5. (create a search page, if necessary, searching just that new field)
  6. verify that searching for a word in the title of node 3 yields node 1 as a result
  7. edit node 3’s title and see if the search reflects the change without manual re-indexing

The attached patch revision adds test coverage on top of #2. Through it, I was also able to determine why that check you removed was there in the first place – without it, it seems the nested :entity property for all entity reference fields causes us to lose the bundle information. A bit awkward to work around, unfortunately – or at least I couldn’t think of a good way to do it. I even had to hard-code the 'entity' property name – but at least it should now work again.
Please test/review!

@ kyuubi: As the original problem still exists, please create a new issue for the performance problem.

drunken monkey’s picture

As there is test coverage for this new functionality, I’m pretty confident it works as designed, but would still be great to get feedback on this before committing.

carolpettirossi’s picture

Sorry for the late reply @drunken monkey. I'll test the patch and get back to you in a day or two.

carolpettirossi’s picture

Status: Needs review » Reviewed & tested by the community

@drunken monkey, I've tested the patch from #19 with dev and it works well. Updating Status to RTBC.

I'll raise a separate ticket for the timeout/performance issue mentioned on #6

drunken monkey’s picture

Status: Reviewed & tested by the community » Fixed

Great to hear, thanks a lot for testing and getting back to me. Sorry that I now produced a further delay at my end.
Anyways, committed. Thanks again!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.