Skip to content

Commit fb9c49d

Browse files
authored
Merge pull request #4536 from xwiki/XWIKI-15166-2
XWIKI-15166: SOLR reindexation job cause serious perfomance issues on large database
2 parents 9ae68b6 + a79395f commit fb9c49d

File tree

10 files changed

+248
-113
lines changed

10 files changed

+248
-113
lines changed

xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-api/src/main/java/org/xwiki/search/solr/internal/job/AbstractDocumentIterator.java

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,12 @@
2121

2222
import javax.inject.Inject;
2323

24+
import org.apache.commons.lang3.builder.EqualsBuilder;
25+
import org.apache.commons.lang3.builder.HashCodeBuilder;
2426
import org.xwiki.model.reference.EntityReference;
27+
import org.xwiki.model.reference.WikiReference;
2528
import org.xwiki.search.solr.internal.api.SolrConfiguration;
29+
import org.xwiki.text.XWikiToStringBuilder;
2630

2731
/**
2832
* Base class for {@link DocumentIterator}s.
@@ -33,6 +37,96 @@
3337
*/
3438
public abstract class AbstractDocumentIterator<T> implements DocumentIterator<T>
3539
{
40+
/**
41+
* A document related entry.
42+
*
43+
* @version $Id$
44+
* @since 17.8.0RC1
45+
*/
46+
public static class DocumentIteratorEntry
47+
{
48+
private final WikiReference wiki;
49+
50+
private final long docId;
51+
52+
private final String version;
53+
54+
protected DocumentIteratorEntry(WikiReference wiki, long docId, String version)
55+
{
56+
this.wiki = wiki;
57+
this.docId = docId;
58+
this.version = version;
59+
}
60+
61+
/**
62+
* @return the reference
63+
*/
64+
public WikiReference getWiki()
65+
{
66+
return wiki;
67+
}
68+
69+
/**
70+
* @return the docId
71+
*/
72+
public long getDocId()
73+
{
74+
return docId;
75+
}
76+
77+
/**
78+
* @return the version
79+
*/
80+
public String getVersion()
81+
{
82+
return version;
83+
}
84+
85+
@Override
86+
public int hashCode()
87+
{
88+
HashCodeBuilder builder = new HashCodeBuilder();
89+
90+
builder.append(getWiki());
91+
builder.append(getDocId());
92+
builder.append(getVersion());
93+
94+
return builder.build();
95+
}
96+
97+
@Override
98+
public boolean equals(Object obj)
99+
{
100+
if (obj instanceof DocumentIteratorEntry otherEntry) {
101+
if (obj == this) {
102+
return true;
103+
}
104+
105+
EqualsBuilder builder = new EqualsBuilder();
106+
107+
builder.append(getWiki(), otherEntry.getWiki());
108+
builder.append(getDocId(), otherEntry.getDocId());
109+
builder.append(getVersion(), otherEntry.getVersion());
110+
111+
return builder.build();
112+
}
113+
114+
return false;
115+
}
116+
117+
@Override
118+
public String toString()
119+
{
120+
XWikiToStringBuilder builder = new XWikiToStringBuilder(this);
121+
122+
builder.append("wiki", getWiki());
123+
builder.append("docId", getDocId());
124+
builder.append("version", getVersion());
125+
126+
return builder.build();
127+
}
128+
}
129+
36130
/**
37131
* Specifies the root entity whose documents are iterated. If {@code null} then all the documents are iterated.
38132
*/

xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-api/src/main/java/org/xwiki/search/solr/internal/job/DatabaseDocumentIterator.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import org.xwiki.query.QueryException;
4848
import org.xwiki.query.QueryFilter;
4949
import org.xwiki.query.QueryManager;
50+
import org.xwiki.search.solr.internal.job.AbstractDocumentIterator.DocumentIteratorEntry;
5051
import org.xwiki.wiki.descriptor.WikiDescriptorManager;
5152
import org.xwiki.wiki.manager.WikiManagerException;
5253

@@ -59,7 +60,7 @@
5960
@Component
6061
@InstantiationStrategy(ComponentInstantiationStrategy.PER_LOOKUP)
6162
@Named("database")
62-
public class DatabaseDocumentIterator extends AbstractDocumentIterator<String>
63+
public class DatabaseDocumentIterator extends AbstractDocumentIterator<DocumentIteratorEntry>
6364
{
6465
/**
6566
* The current index in the list of {@link #results}.
@@ -130,20 +131,24 @@ public boolean hasNext()
130131
}
131132

132133
@Override
133-
public Pair<DocumentReference, String> next()
134+
public Pair<DocumentReference, DocumentIteratorEntry> next()
134135
{
135136
Object[] result = getResults().get(index++);
137+
136138
String localSpaceReference = (String) result[0];
137139
String name = (String) result[1];
138140
String locale = (String) result[2];
139-
String version = (String) result[3];
140141
SpaceReference spaceReference = new SpaceReference(this.explicitEntityReferenceResolver
141142
.resolve(localSpaceReference, EntityType.SPACE, new WikiReference(wiki)));
142143
DocumentReference documentReference = new DocumentReference(name, spaceReference);
143144
if (!StringUtils.isEmpty(locale)) {
144145
documentReference = new DocumentReference(documentReference, LocaleUtils.toLocale(locale));
145146
}
146-
return new ImmutablePair<DocumentReference, String>(documentReference, version);
147+
String version = (String) result[3];
148+
long docId = (long) result[4];
149+
150+
return new ImmutablePair<>(documentReference,
151+
new DocumentIteratorEntry(documentReference.getWikiReference(), docId, version));
147152
}
148153

149154
@Override

xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-api/src/main/java/org/xwiki/search/solr/internal/job/DiffDocumentIterator.java

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,19 @@
2020
package org.xwiki.search.solr.internal.job;
2121

2222
import java.util.Comparator;
23-
import java.util.Objects;
2423

2524
import org.apache.commons.lang3.tuple.ImmutablePair;
2625
import org.apache.commons.lang3.tuple.Pair;
27-
import org.xwiki.model.internal.reference.DefaultSymbolScheme;
28-
import org.xwiki.model.internal.reference.LocalStringEntityReferenceSerializer;
2926
import org.xwiki.model.reference.DocumentReference;
3027
import org.xwiki.model.reference.EntityReference;
31-
import org.xwiki.model.reference.EntityReferenceSerializer;
3228

3329
/**
3430
* Compares the list of document references from two document iterators.
3531
*
36-
* @param <T> the type of data used to determine if a document is up to date
3732
* @version $Id$
3833
* @since 5.4.5
3934
*/
40-
public class DiffDocumentIterator<T> extends AbstractDocumentIterator<DiffDocumentIterator.Action>
35+
public class DiffDocumentIterator extends AbstractDocumentIterator<DiffDocumentIterator.Action>
4136
{
4237
/**
4338
* The action that must be taken in order to move from the previous version to the next version.
@@ -60,27 +55,27 @@ public enum Action
6055
/**
6156
* The document iterator that corresponds to the previous state (the store that needs to be updated).
6257
*/
63-
private final DocumentIterator<T> previous;
58+
private final DocumentIterator<DocumentIteratorEntry> previous;
6459

6560
/**
6661
* The document iterator that corresponds to the next state (the store that is used as a reference point).
6762
*/
68-
private final DocumentIterator<T> next;
63+
private final DocumentIterator<DocumentIteratorEntry> next;
6964

7065
/**
7166
* Used to compare document references.
7267
*/
73-
private final Comparator<DocumentReference> documentReferenceComparator = getComparator();
68+
private final Comparator<DocumentIteratorEntry> entryComparator = getComparator();
7469

7570
/**
7671
* The last entry taken from the {@link #previous} iterator.
7772
*/
78-
private Pair<DocumentReference, T> previousEntry;
73+
private Pair<DocumentReference, DocumentIteratorEntry> previousEntry;
7974

8075
/**
8176
* The last entry taken from the {@link #next} iterator.
8277
*/
83-
private Pair<DocumentReference, T> nextEntry;
78+
private Pair<DocumentReference, DocumentIteratorEntry> nextEntry;
8479

8580
/**
8681
* The last compare result between {@link #previousEntry} and {@link #nextEntry}.
@@ -94,7 +89,8 @@ public enum Action
9489
* @param next the document iterator that corresponds to the next state (the store that is used as a reference
9590
* point)
9691
*/
97-
public DiffDocumentIterator(DocumentIterator<T> previous, DocumentIterator<T> next)
92+
public DiffDocumentIterator(DocumentIterator<DocumentIteratorEntry> previous,
93+
DocumentIterator<DocumentIteratorEntry> next)
9894
{
9995
this.previous = previous;
10096
this.next = next;
@@ -125,7 +121,7 @@ public Pair<DocumentReference, Action> next()
125121
if (diff <= 0) {
126122
previousEntry = previous.next();
127123
}
128-
diff = documentReferenceComparator.compare(previousEntry.getKey(), nextEntry.getKey());
124+
diff = entryComparator.compare(previousEntry.getValue(), nextEntry.getValue());
129125
if (diff == 0) {
130126
documentReference = nextEntry.getKey();
131127
// Compare the document version.
@@ -157,15 +153,9 @@ public Pair<DocumentReference, Action> next()
157153
*
158154
* @return the comparator for comparing document references
159155
*/
160-
public static Comparator<DocumentReference> getComparator()
156+
public static Comparator<DocumentIteratorEntry> getComparator()
161157
{
162-
EntityReferenceSerializer<String> localEntityReferenceSerializer =
163-
new LocalStringEntityReferenceSerializer(new DefaultSymbolScheme());
164-
return Comparator.comparing(DocumentReference::getWikiReference)
165-
// Compare by the whole space as string as this is also what we compare in the database and in Solr.
166-
.thenComparing(documentReference -> localEntityReferenceSerializer.serialize(documentReference.getParent()))
167-
.thenComparing(DocumentReference::getName)
168-
.thenComparing(documentReference -> Objects.toString(documentReference.getLocale(), ""));
158+
return Comparator.comparing(DocumentIteratorEntry::getWiki).thenComparing(DocumentIteratorEntry::getDocId);
169159
}
170160

171161
@Override

xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-api/src/main/java/org/xwiki/search/solr/internal/job/IndexerJob.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.xwiki.search.solr.internal.api.SolrIndexer;
4343
import org.xwiki.search.solr.internal.api.SolrIndexerException;
4444
import org.xwiki.search.solr.internal.api.SolrInstance;
45+
import org.xwiki.search.solr.internal.job.AbstractDocumentIterator.DocumentIteratorEntry;
4546
import org.xwiki.search.solr.internal.job.DiffDocumentIterator.Action;
4647
import org.xwiki.search.solr.internal.reference.SolrReferenceResolver;
4748

@@ -74,11 +75,11 @@ public class IndexerJob extends AbstractJob<IndexerRequest, DefaultJobStatus<Ind
7475

7576
@Inject
7677
@Named("database")
77-
private transient DocumentIterator<String> databaseIterator;
78+
private transient DocumentIterator<DocumentIteratorEntry> databaseIterator;
7879

7980
@Inject
8081
@Named("solr")
81-
private transient DocumentIterator<String> solrIterator;
82+
private transient DocumentIterator<DocumentIteratorEntry> solrIterator;
8283

8384
@Inject
8485
private EntityReferenceSerializer<String> entityReferenceSerializer;
@@ -125,7 +126,7 @@ protected void runInternal() throws Exception
125126
*/
126127
private void updateSolrIndex() throws Exception
127128
{
128-
DiffDocumentIterator<String> iterator = new DiffDocumentIterator<>(this.solrIterator, this.databaseIterator);
129+
DiffDocumentIterator iterator = new DiffDocumentIterator(this.solrIterator, this.databaseIterator);
129130
iterator.setRootReference(getRequest().getRootReference());
130131

131132
this.progressManager.pushLevelProgress(2, this);
@@ -147,7 +148,7 @@ private void updateSolrIndex() throws Exception
147148
}
148149
}
149150

150-
private void updateSolrIndex(int progressSize, DiffDocumentIterator<String> iterator) throws Exception
151+
private void updateSolrIndex(int progressSize, DiffDocumentIterator iterator) throws Exception
151152
{
152153
this.progressManager.pushLevelProgress(progressSize, this);
153154

xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-api/src/main/java/org/xwiki/search/solr/internal/job/SolrDocumentIterator.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.xwiki.search.solr.internal.api.FieldUtils;
4343
import org.xwiki.search.solr.internal.api.SolrIndexerException;
4444
import org.xwiki.search.solr.internal.api.SolrInstance;
45+
import org.xwiki.search.solr.internal.job.AbstractDocumentIterator.DocumentIteratorEntry;
4546
import org.xwiki.search.solr.internal.reference.SolrReferenceResolver;
4647

4748
/**
@@ -53,7 +54,7 @@
5354
@Component
5455
@InstantiationStrategy(ComponentInstantiationStrategy.PER_LOOKUP)
5556
@Named("solr")
56-
public class SolrDocumentIterator extends AbstractDocumentIterator<String>
57+
public class SolrDocumentIterator extends AbstractDocumentIterator<DocumentIteratorEntry>
5758
{
5859
private static final String SOLR_ANYVALUE = "[* TO *]";
5960

@@ -94,12 +95,16 @@ public boolean hasNext()
9495
}
9596

9697
@Override
97-
public Pair<DocumentReference, String> next()
98+
public Pair<DocumentReference, DocumentIteratorEntry> next()
9899
{
99-
SolrDocument result = getResults().get(index++);
100+
SolrDocument result = getResults().get(this.index++);
101+
100102
DocumentReference documentReference = this.solrDocumentReferenceResolver.resolve(result);
103+
long docId = (long) result.getFieldValue(FieldUtils.DOC_ID);
101104
String version = (String) result.get(FieldUtils.VERSION);
102-
return new ImmutablePair<DocumentReference, String>(documentReference, version);
105+
106+
return new ImmutablePair<>(documentReference,
107+
new DocumentIteratorEntry(documentReference.getWikiReference(), docId, version));
103108
}
104109

105110
@Override
@@ -144,7 +149,7 @@ private SolrQuery getQuery() throws SolrIndexerException
144149
if (query == null) {
145150
query = new SolrQuery(solrReferenceResolver.getQuery(rootReference));
146151
query.setFields(FieldUtils.WIKI, FieldUtils.SPACES, FieldUtils.NAME, FieldUtils.DOCUMENT_LOCALE,
147-
FieldUtils.VERSION);
152+
FieldUtils.VERSION, FieldUtils.DOC_ID);
148153
query.addFilterQuery(FieldUtils.TYPE + ':' + EntityType.DOCUMENT.name());
149154
// Make sure to skip invalid documents, they will be re-indexed
150155
query.addFilterQuery(FieldUtils.WIKI + ':' + SOLR_ANYVALUE);

0 commit comments

Comments
 (0)